package com.yanqu.road.server.manager.activity.feast.activity;

import com.alibaba.fastjson.JSON;
import com.yanqu.road.dao.impl.activity.feast.*;
import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.activity.feast.config.FeastPvpPlaceConfig;
import com.yanqu.road.entity.activity.feast.config.FeastStateConfig;
import com.yanqu.road.entity.activity.feast.data.*;
import com.yanqu.road.entity.activity.feast.data.helper.CrossFeastNpcDataHelper;
import com.yanqu.road.entity.activity.feast.data.helper.CrossFeastPvpAttackHelper;
import com.yanqu.road.entity.activity.feast.pvp.Coordinate;
import com.yanqu.road.entity.activity.feast.pvp.FeastPvpBirthData;
import com.yanqu.road.entity.enums.eGamePlayerEventType;
import com.yanqu.road.entity.enums.eMessageType;
import com.yanqu.road.entity.enums.feast.eFeastPvpNoticeType;
import com.yanqu.road.entity.enums.feast.eFeastType;
import com.yanqu.road.entity.log.cross.feast.LogFeastAddScore;
import com.yanqu.road.entity.log.cross.feast.LogFeastPvpApply;
import com.yanqu.road.entity.log.cross.feast.LogFeastPvpKill;
import com.yanqu.road.entity.log.cross.feast.LogFeastPvpSettle;
import com.yanqu.road.entity.player.CrossUserBaseInfo;
import com.yanqu.road.entity.player.UserBaseInfo;
import com.yanqu.road.logic.helper.ActivityHelper;
import com.yanqu.road.logic.pb.CrossShanHeFeastPb;
import com.yanqu.road.logic.pb.PlayerBasePb;
import com.yanqu.road.message.YanQuMessage;
import com.yanqu.road.pb.activity.ShanHeFeastProto;
import com.yanqu.road.pb.cross.activity.CrossActivityProto;
import com.yanqu.road.pb.worldmessage.WorldMessageProto;
import com.yanqu.road.server.logic.MessageHelper;
import com.yanqu.road.server.manager.activity.feast.CrossFeastMgr;
import com.yanqu.road.server.manager.activity.feast.logic.CrossFeastChatLogic;
import com.yanqu.road.server.manager.log.CrossAutoLogMgr;
import com.yanqu.road.server.manager.npc.CrossNpcUserMgr;
import com.yanqu.road.server.manager.user.CrossUserMgr;
import com.yanqu.road.server.protocol.ClientProtocol;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.GameProtocol;
import com.yanqu.road.server.protocol.Protocol;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.YanQuMessageUtils;
import com.yanqu.road.utils.config.Config;
import com.yanqu.road.utils.date.DateHelper;
import com.yanqu.road.utils.string.StringUtils;
import io.netty.util.internal.ConcurrentSet;
import org.apache.mina.util.ConcurrentHashSet;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 山河乐宴
 */
public class CrossFeastActivity extends CrossFeastBaseActivity {

    private RandomHelper randomHelper = new RandomHelper();

    /**
     * 活动总数据
     */
    private CrossFeastPvpData crossFeastPvpData;

    /**
     * 本轮报名名单 ,每轮重置
     */
    private CrossFeastRankListModel applyRankListModel = new CrossFeastRankListModel();

    /**
     * 所有轮此的榜单
     */
    private Map<Integer, CrossFeastRankListModel> roundRankListModel = new ConcurrentHashMap<>();

    /**
     * pvp玩家数据     userId,玩家数据
     */
    private Map<Long, CrossFeastPvpUserData> pvpUserDataMap = new ConcurrentHashMap<>();

    /**
     * 宝地(房间)信息    placeId,房间信息
     */
    private Map<Integer, CrossFeastPvpPlaceData> pvpPlaceDataMap = new ConcurrentHashMap<>();

    /**
     * 个人战绩榜单
     */
    private CrossFeastRankListModel userScoreRank = new CrossFeastRankListModel();

    /**
     * 个人仙力榜单
     */
    private CrossFeastRankListModel userPowerRank = new CrossFeastRankListModel();

    /**
     * 榜单锁定同步情况
     */
    private Map<Long, CrossFeastMountAllotData> mountAllotDataMap = new ConcurrentHashMap<>();

    /**
     * 榜单锁定情况
     */
    private Map<Long, Map<Long, Integer>> allotMap = new ConcurrentHashMap<>();

    private Set<Long> inPvpActivity = new ConcurrentSet<>();

    private CrossFeastChatLogic chatLogic;

    /**
     * 全服公告
     */
    public LinkedList<CrossFeastPvpNoticeData> noticeDataList = new LinkedList<>();

    /**
     * 历练界面用户, 玩家id
     */

    private Set<Long> practiceUserSet = new HashSet<>();

    /**
     * 攻击同步列表      placeId,List
     */
    private Map<Integer, List<CrossFeastPvpAttackHelper>> attackSyncListMap = new ConcurrentHashMap<>();

    /**
     * 晋级、降级消息列表  placeId,List
     */
    private Map<Integer, List<ShanHeFeastProto.FeastUpDownDemandTemp>> demandSyncListMap = new ConcurrentHashMap<>();

    /**
     * 房间技能列表
     */
    private Map<Integer, List<ShanHeFeastProto.FeastPlaceOptTemp>> optSyncListMap = new ConcurrentHashMap<>();

    /**
     * 房间玩家
     */
    private Map<Integer, ConcurrentHashSet<Long>> roomUserMap = new ConcurrentHashMap<>();

    private void addRoomUser(int roomId, long userId) {
        synchronized (roomUserMap) {
            ConcurrentHashSet<Long> userSet = roomUserMap.getOrDefault(roomId, new ConcurrentHashSet<>());
            userSet.add(userId);
            roomUserMap.put(roomId, userSet);
        }
    }

    private void removeRoomUser(int roomId, long userId) {
        synchronized (roomUserMap) {
            ConcurrentHashSet<Long> userSet = roomUserMap.getOrDefault(roomId, new ConcurrentHashSet<>());
            userSet.remove(userId);
            roomUserMap.put(roomId, userSet);
        }
    }

    public CrossFeastRankListModel getRoundRank(int round){
        CrossFeastRankListModel model = roundRankListModel.get(round);
        if(model == null){
            synchronized (roundRankListModel){
                model = roundRankListModel.get(round);
                if(model == null){
                    model = new CrossFeastRankListModel();
                    roundRankListModel.put(round, model);
                }
            }
        }
        return model;
    }

    /**
     * 获取房间用户数据
     *
     * @param roomId 房间id
     */
    private ConcurrentHashSet<Long> getRoomUserList(int roomId) {
        ConcurrentHashSet<Long> userSet = roomUserMap.get(roomId);
        if(userSet == null){
            synchronized (roomUserMap){
                userSet = roomUserMap.get(roomId);
                if(userSet == null){
                    userSet = new ConcurrentHashSet<>();
                    roomUserMap.put(roomId, userSet);
                }
            }
        }
        return new ConcurrentHashSet<>(userSet);
    }

    /**
     * npc攻击开关
     */
    private boolean npcAttack = true;

    /**
     * npc自动复活
     */
    private boolean npcRevive = true;

    /**
     * 玩家锁
     */
    private static final Map<Long, Object> playerLockMap = new ConcurrentHashMap<>();

    /**
     * 房间锁
     */
    private static final Map<Integer, Object> placeLockMap = new ConcurrentHashMap<>();

    /**
     * 获取玩家锁
     */
    private static Object getPlayerLock(long userId) {
        if (!playerLockMap.containsKey(userId)) {
            synchronized (playerLockMap) {
                if (!playerLockMap.containsKey(userId)) {
                    playerLockMap.put(userId, new Object());
                }
            }
        }
        return playerLockMap.get(userId);
    }


    /**
     * 获取房间锁
     */
    private static Object getPlaceLock(int placeId) {
        if (!placeLockMap.containsKey(placeId)) {
            synchronized (placeLockMap) {
                if (!placeLockMap.containsKey(placeId)) {
                    placeLockMap.put(placeId, new Object());
                }
            }
        }
        return placeLockMap.get(placeId);
    }


    public CrossFeastActivity(ActivityInfo activityInfo) {
        super(activityInfo);
        // 读数据
        int curRound = getCurRound();
        crossFeastPvpData = new CrossFeastPvpDataDaoImpl().getCrossFeastPvpData(activityInfo.getActivityId());
        if (crossFeastPvpData == null) {
            // 初始化
            crossFeastPvpData = new CrossFeastPvpData();
            crossFeastPvpData.setActivityId(activityInfo.getActivityId());
            crossFeastPvpData.setLockState(false);
            crossFeastPvpData.setRound(curRound);
            crossFeastPvpData.setSettle(false);
            crossFeastPvpData.setUpdateTime(System.currentTimeMillis());
            crossFeastPvpData.setInsertOption();
        }
        // pvp玩家数据
        pvpUserDataMap = new CrossFeastPvpUserDataDaoImpl().getCrossFeastPvpUserDataMap(activityInfo.getActivityId());
        // pvp房间信息
        pvpPlaceDataMap = new CrossFeastPvpPlaceDataDaoImpl().getCrossFeastPvpPlaceDataMap(activityInfo.getActivityId());
        initPlaceData();
        // 获取本轮全服公告
        int limitNotice = config.getFEAST_PVP_NOTICE_NUM();
        noticeDataList = new CrossFeastPvpNoticeDataDaoImpl().getCrossFeastPvpNoticeDataList(activityInfo.getActivityId(), curRound, 0, limitNotice);
        Collections.reverse(noticeDataList);

        // 灵峰分配相关信息
        mountAllotDataMap = new CrossFeastMountAllotDataDaoImpl().getCrossFeastMountAllotData(activityInfo.getActivityId());

        // 加到内存房间里
        for (CrossFeastPvpUserData userData : pvpUserDataMap.values()) {
            if (userData.isApply() && userData.isPvpAble()) {
                addRoomUser(userData.getPlaceId(), userData.getUserId());
            }
        }

        // 初始化榜单
        initAllRankList();

        chatLogic = new CrossFeastChatLogic(activityInfo);
    }


    /**
     * 初始化房间信息
     */
    private void initPlaceData() {
        for (FeastPvpPlaceConfig placeConfig : config.getPlaceConfigMap().values()) {
            if (placeConfig == null) {
                continue;
            }
            int placeId = placeConfig.getId();
            synchronized (getPlaceLock(placeId)) {
                if (!pvpPlaceDataMap.containsKey(placeId)) {
                    CrossFeastPvpPlaceData pvpPlaceData = new CrossFeastPvpPlaceData();
                    pvpPlaceData.setActivityId(config.getActivityInfo().getActivityId());
                    pvpPlaceData.setPlaceId(placeId);
                    pvpPlaceData.setInsertOption();
                    pvpPlaceDataMap.put(placeId, pvpPlaceData);
                }
            }
            CrossFeastPvpPlaceData pvpPlaceData = pvpPlaceDataMap.get(placeId);
            initPlaceData(pvpPlaceData);
        }
    }


    /**
     * 获取宝地信息
     *
     * @param placeId 宝地id
     */
    private CrossFeastPvpPlaceData getPvpPlace(int placeId) {
        return pvpPlaceDataMap.get(placeId);
    }

    /**
     * 加入到房间中
     * @param placeId     宝地id
     * @param pvpUserData 用户数据
     */
    private void joinPlace(int placeId, CrossFeastPvpUserData pvpUserData) {
        if (pvpUserData == null) {
            return;
        }
        if (placeId == 0) {
            return;
        }
        if(pvpUserData.getPlaceId() > 0 && pvpUserData.getPlaceId() != placeId){
            removeRoomUser(pvpUserData.getPlaceId(), pvpUserData.getUserId());
        }
        addRoomUser(placeId, pvpUserData.getUserId());

        pvpUserData.setPlaceId(placeId);

        FeastPvpPlaceConfig placeConfig = config.getPlaceConfigMap().get(placeId);

        FeastPvpBirthData birthData = randomBirth(placeId);

        pvpUserData.getPosition().setX(calcX(birthData.getCoordinate().getX(), placeConfig, pvpUserData.getProfileRadius()));
        pvpUserData.getPosition().setY(calcY(birthData.getCoordinate().getY(), placeConfig, pvpUserData.getProfileRadius()));
        pvpUserData.getPosition().setDirX(0);
        pvpUserData.getPosition().setDirY(0);
        pvpUserData.getPosition().setTime(System.currentTimeMillis());

        pvpUserData.setUpdateOption();

        // 广播位置
        addPlayerPosition(pvpUserData.getPlaceId(), pvpUserData.getUserId(), pvpUserData.getPosition());
        // 通知
        sendJoinPositionSyncMsg(pvpUserData);
    }

    /**
     * 变更房间
     * @param type
     */
    public void leavePlace(CrossFeastPvpUserData pvpUserData, int type) {
        if (pvpUserData == null) {
            return;
        }
        long userId = pvpUserData.getUserId();
        int placeId = pvpUserData.getPlaceId();
        if (placeId == 0) {
            return;
        }
        removeRoomUser(placeId, userId);
        addRoomUser(pvpUserData.getPlaceId(), userId);

        // 需要通知房间内的用户
        Set<Long> notifyUserList = getRoomUserList(placeId);

        // 通知
        ShanHeFeastProto.FeastLeavePlaceSync.Builder syncMsg = ShanHeFeastProto.FeastLeavePlaceSync.newBuilder();
        syncMsg.setUserId(userId);
        syncMsg.setType(type);
//        sendPacketToAll(Protocol.U_SHAN_HE_FEAST_LEAVE_PLACE_SYNC, syncMsg, notifyUserList);
    }

    /**
     * 移除npc
     */
    private void removeNpc(long userId) {
        if (!isNpc(userId)) {
            return;
        }
        npcUserMap.remove(userId);
        npcDataMap.remove(userId);
    }

    public void reloadConfig() {
        loadConfigFromDb(config.getActivityInfo());
        for (Map.Entry<Integer, CrossFeastPvpPlaceData> entry : pvpPlaceDataMap.entrySet()) {
            CrossFeastPvpPlaceData value = entry.getValue();
            initPlaceData(value);
        }
    }

    public void save() {
        // 保存活动数据
        if (crossFeastPvpData != null) {
            if (crossFeastPvpData.isInsertOption()) {
                new CrossFeastPvpDataDaoImpl().add(crossFeastPvpData);
            } else if (crossFeastPvpData.isUpdateOption()) {
                new CrossFeastPvpDataDaoImpl().update(crossFeastPvpData);
            }
        }
        // 保存用户数据
        for (CrossFeastPvpUserData pvpUserData : pvpUserDataMap.values()) {
            if (pvpUserData.isInsertOption()) {
                new CrossFeastPvpUserDataDaoImpl().add(pvpUserData);
            } else if (pvpUserData.isUpdateOption()) {
                new CrossFeastPvpUserDataDaoImpl().update(pvpUserData);
            }
        }
        // 保存宝地数据
        for (CrossFeastPvpPlaceData pvpPlaceData : pvpPlaceDataMap.values()) {
            if (pvpPlaceData.isInsertOption()) {
                new CrossFeastPvpPlaceDataDaoImpl().add(pvpPlaceData);
            } else if (pvpPlaceData.isUpdateOption()) {
                new CrossFeastPvpPlaceDataDaoImpl().update(pvpPlaceData);
            }
        }
        // 保存全服公告记录
        LinkedList<CrossFeastPvpNoticeData> tempNoticeDataList = new LinkedList<>(noticeDataList);
        for (CrossFeastPvpNoticeData noticeData : tempNoticeDataList) {
            if (noticeData.isInsertOption()) {
                new CrossFeastPvpNoticeDataDaoImpl().add(noticeData);
            }
        }

        // 保存排行锁定数据
        for (CrossFeastMountAllotData mountAllotData : mountAllotDataMap.values()) {
            if (mountAllotData.isInsertOption()) {
                new CrossFeastMountAllotDataDaoImpl().add(mountAllotData);
            } else if (mountAllotData.isUpdateOption()) {
                new CrossFeastMountAllotDataDaoImpl().update(mountAllotData);
            }
        }
    }

    /**
     * 用户数据更新
     */
    public void pvePropertyChange(ShanHeFeastProto.CrossFeastPvePropertyChangeReqMsg temp) {
        CrossFeastPvpUserData userData = getPvpUserData(temp.getUserId());
        if (userData != null) {
            // 更新属性
            FeastPveUserProperty property = parseFeastUserPveProperty(temp.getPveProperty());
            // 境界或者仙力变更才更新
            if (userData.getPveProperty().getStateId() != property.getStateId() || userData.getPveProperty().getPowerVal() != property.getPowerVal()) {
                userData.setUpdatePropertyTime(System.currentTimeMillis());
            }
            userData.setPveProperty(property);
            if (!(userData.getPveProperty().getStateId() <= config.getInitStateId() && userData.getPveProperty().getPowerVal() <= 0L)) {
                // 更新个人仙力榜单
                CrossFeastRank rank = new CrossFeastRank(String.valueOf(userData.getUserId()), property.getStateId(), userData.getUpdatePropertyTime(), String.valueOf(property.getPowerVal()));
                userPowerRank.rankChange(rank);
            }
            boolean isLoginSync = temp.getIsLoginSync();
            if (isLoginSync) {
                // 是否登录同步
                loginSyncDataToGame(userData);
            }

            if(userData.isApply() && isApplyTime()){
                // 更新榜单
                applyRankListModel.rankChange(new CrossFeastRank(String.valueOf(userData.getUserId()), userData.getPveProperty().getStateId(), userData.getUpdatePropertyTime(), String.valueOf(userData.getPveProperty().getPowerVal())));
            }
        }

    }
    /**
     *
     * 登录同步数据到游戏服
     */
    public void loginSyncDataToGame(CrossFeastPvpUserData pvpUserData) {
        ShanHeFeastProto.FeastSyncLoginDataRespMsg.Builder respMsg = ShanHeFeastProto.FeastSyncLoginDataRespMsg.newBuilder();
        respMsg.setCampId(pvpUserData.getCampId());
        sendPacket(GameProtocol.S_SHAN_HE_FEAST_SYNC_LOGIN_FROM_CROSS, respMsg, pvpUserData.getUserId());
    }

    /**
     * 初始化pvp用户数据
     */
    private CrossFeastPvpUserData getPvpUserData(long userId) {
        if (userId == 0) {
            return null;
        }
        if (isRobot(userId)){
            return robotUserMap.get(userId);
        }
        if (isNpc(userId)) {
            return npcUserMap.get(userId);
        }
        // 不存在则初始化
        if (!pvpUserDataMap.containsKey(userId)) {
            synchronized (getPlayerLock(userId)) {
                if (!pvpUserDataMap.containsKey(userId)) {

                    long nowTime = System.currentTimeMillis();
                    CrossFeastPvpUserData pvpUserData = new CrossFeastPvpUserData();
                    pvpUserData.setActivityId(config.getActivityInfo().getActivityId());
                    pvpUserData.setUserId(userId);

                    // 出生地id
                    pvpUserData.setPlaceId(0);
                    // 可传送时间
                    pvpUserData.setTransferTime(nowTime);
                    // 可复活时间
                    pvpUserData.setReviveTime(nowTime);
                    // 生命标识
                    pvpUserData.setReviveCnt(0);

                    pvpUserData.setInsertOption();
                    pvpUserDataMap.put(userId, pvpUserData);
                }
            }
        }
        return pvpUserDataMap.get(userId);
    }

    /**
     * 获取当前为第几轮
     */
    public int getCurRound() {
        return DateHelper.calc2DateTDOADays(new Date(config.getActivityInfo().getBeginTime() * 1000), new Date());
    }

    /**
     * 空任务事件,10秒一次
     */
    public void crossFeastEmptyTask() {
        if(Config.isDebug()) {
            logger.info("crossFeastEmptyTask");
            if(!isBattleTime()){
                return;
            }
            for (Map.Entry<Integer, ConcurrentHashSet<Long>> entry : roomUserMap.entrySet()) {
                ConcurrentHashSet<Long> value = entry.getValue();
                logger.info("房间{}，人数{}", entry.getKey(), JSON.toJSONString(value));
            }
        }
    }

    /**
     * 挨打同步
     */
    public void crossFeastSyncAttackTask() {
        if (!isBattleTime()) {
            return;
        }
        for (int placeId : pvpPlaceDataMap.keySet()) {
            syncPlaceAttack(placeId);
            syncPlaceUpDownDemand(placeId);
            syncPlaceOpt(placeId);
        }
    }

    /**
     * 同步房间被打记录
     */
    private void syncPlaceAttack(int placeId) {
        ShanHeFeastProto.FeastAttackedSyncMsg.Builder attackedSyncMsg = ShanHeFeastProto.FeastAttackedSyncMsg.newBuilder();
        CrossFeastPvpPlaceData placeData = getPvpPlace(placeId);
        if (placeData == null) {
            return;
        }
        synchronized (attackSyncListMap) {
            if (!attackSyncListMap.containsKey(placeId)) {
                return;
            }
            List<CrossFeastPvpAttackHelper> attackList = attackSyncListMap.get(placeId);
            if (attackList.size() == 0) {
                return;
            }
            for (CrossFeastPvpAttackHelper helper : attackList) {
                attackedSyncMsg.addAttack(parseFeastAttackedTemp(helper));
            }
            // 清空记录
            attackSyncListMap.put(placeId, new ArrayList<>());
        }
        // 同步给房间的用户
        sendPacketToAll(ClientProtocol.U_SHAN_HE_FEAST_ATTACKED_SYNC, attackedSyncMsg, getRoomUserListSync(placeId));
    }

    /**
     * 同步晋级、降级
     */
    private void syncPlaceUpDownDemand(int placeId) {
        ShanHeFeastProto.FeastUpDownDemandSync.Builder syncMsg = ShanHeFeastProto.FeastUpDownDemandSync.newBuilder();
        CrossFeastPvpPlaceData placeData = getPvpPlace(placeId);
        if (placeData == null) {
            return;
        }
        ConcurrentHashSet<Long> roomUserList = getRoomUserListSync(placeId);
        synchronized (demandSyncListMap) {
            if (!demandSyncListMap.containsKey(placeId)) {
                return;
            }
            List<ShanHeFeastProto.FeastUpDownDemandTemp> attackList = demandSyncListMap.get(placeId);
            if (attackList.size() == 0) {
                return;
            }
            syncMsg.setPlaceId(placeId);
            for (ShanHeFeastProto.FeastUpDownDemandTemp temp : attackList) {
                syncMsg.addUser(temp);
            }
            // 清空记录
            demandSyncListMap.put(placeId, new ArrayList<>());
        }
        // 同步给房间的用户
        sendPacketToAll(ClientProtocol.U_SHAN_HE_FEAST_PLACE_UP_DOWN_SYNC, syncMsg, roomUserList);
    }

    /**
     * 同步房间操作
     */
    public void syncRoomOpTask() {
        if (!isBattleTime()) {
            return;
        }
        for (int placeId : pvpPlaceDataMap.keySet()) {
            syncPlaceOpt(placeId);
        }
    }

    /**
     * 同步房间操作
     */
    private void syncPlaceOpt(int placeId) {
        ShanHeFeastProto.FeastPlaceOptSyncMsg.Builder syncMsg = ShanHeFeastProto.FeastPlaceOptSyncMsg.newBuilder();
        CrossFeastPvpPlaceData placeData = getPvpPlace(placeId);
        if (placeData == null) {
            return;
        }
        ConcurrentHashSet<Long> roomUserList = getRoomUserListSync(placeId);

        synchronized (optSyncListMap) {
            if (!optSyncListMap.containsKey(placeId)) {
                return;
            }
            List<ShanHeFeastProto.FeastPlaceOptTemp> attackList = optSyncListMap.get(placeId);
            if (attackList.size() == 0) {
                return;
            }
            for (ShanHeFeastProto.FeastPlaceOptTemp temp : attackList) {
                syncMsg.addOpt(temp);
            }
            // 清空记录
            optSyncListMap.put(placeId, new ArrayList<>());
        }
        // 同步给房间的用户
        sendPacketToAll(ClientProtocol.U_SHAN_HE_FEAST_SYNC_SKILL, syncMsg, roomUserList);
    }

    public void crossFeastNpcReviveTask() {
        if (!isBattleTime()) {
            return;
        }
        if (!npcRevive) {
            return;
        }
        long nowTime = System.currentTimeMillis();

        if (npcRevive) {
            // 复活机器人进入房间
            for (Long userId : npcUserMap.keySet()) {
                synchronized (getPlayerLock(userId)) {
                    CrossFeastPvpUserData userData = npcUserMap.get(userId);
                    if (userData.getPlaceId() == 0) {
                        // 没到复活时间
                        if (nowTime < userData.getReviveTime()) {
                            continue;
                        }
                        // 复活
                        revive(userData);
                        // 离开旧房间
                        leavePlace(userData, 4);
                        // 随机加入房间
                        joinPlace(randomHelper.next(pvpPlaceDataMap.size())  + 1, userData);
                        userData.setTransferTime(nowTime + DateHelper.SECOND_MILLIONS * config.getFEAST_PVP_DELIVERY_CD());
                    } else {
                        if (nowTime > userData.getTransferTime() && nowTime > userData.getAttackTime() + DateHelper.SECOND_MILLIONS * 10) {
                            // 离开旧房间
                            leavePlace(userData, 4);
                            // 随机加入房间
                            joinPlace(randomHelper.next(5, 19), userData);
                            userData.setTransferTime(nowTime + DateHelper.SECOND_MILLIONS * config.getFEAST_PVP_DELIVERY_CD());
                        }
                    }
                }
            }
        }
    }


    /**
     * 检测房间用户心跳
     */
    public void crossFeastCheckPlacePing() {
    }


    /**
     * 活动数据检测 轮次切换需重置数据
     */
    public void crossFeastPvpActivityCheckTask() {

        // 判断是否切换轮次
        int curRound = getCurRound();
        if (curRound != crossFeastPvpData.getRound()) {
            // 切换轮次
            changeRound();
        }

        long nowTime = System.currentTimeMillis();

        // 检测下结束公告
        List<String> noticeParamList = StringUtils.stringToStringList(config.getFEAST_PVP_NOTICE_BATTLE_END_TIME(), "\\|");
        boolean endNotice = Integer.parseInt(noticeParamList.get(0)) == 1;
        if(endNotice){
            String params = noticeParamList.get(1);
            List<Integer> paramList = StringUtils.stringToIntegerList(params, ";");

            for (Integer time : paramList) {
                if(crossFeastPvpData.getEndNoticeTimeList().contains(time)){
                    continue;
                }
                if(nowTime >= getBattleEndTime() - time * DateHelper.SECOND_MILLIONS){
                    // 添加公告
                    CrossFeastPvpNoticeData noticeData = new CrossFeastPvpNoticeData();
                    noticeData.setActivityId(config.getActivityInfo().getActivityId());
                    noticeData.setRound(getCurRound());
                    noticeData.setNoticeType(eFeastPvpNoticeType.PvpTimeEnd.getValue());
                    noticeData.setContent(String.valueOf(time / 60));
                    noticeData.setNoticeTime(nowTime);
                    noticeData.setIsRoll(Integer.parseInt(noticeParamList.get(0)));
                    addPvpNoticeData(noticeData, 0, 0);
                    crossFeastPvpData.getEndNoticeTimeList().add(time);
                    break;
                }
            }
        }

        crossFeastLockDataTask();
    }

    /**
     * 切换轮次
     */
    private void changeRound() {
        int curRound = getCurRound();
        crossFeastPvpData.setRound(curRound);
        crossFeastPvpData.setLockState(false);
        crossFeastPvpData.setSettle(false);
        crossFeastPvpData.setEndNoticeTimeList(new ArrayList<>());
        crossFeastPvpData.setUpdateTime(System.currentTimeMillis());

        // 重置房间信息
        resetPlaceData();

        // 重置玩家信息
        resetUserData();

        // 重置榜单相关
        applyRankListModel = new CrossFeastRankListModel();

        // 内存房间用户
        roomUserMap = new ConcurrentHashMap<>();
        // 重置公告
        noticeDataList = new LinkedList<>();

        //清理机器人
        robotUserMap.clear();
        robotDataMap.clear();
        robotId = 1000000;

        npcUserMap.clear();
        npcDataMap.clear();
        npcId = 1;
    }

    private void resetPlaceData(){
        for (CrossFeastPvpPlaceData placeData : pvpPlaceDataMap.values()) {
            // 保险一点再清一下
            placeData.clearData();
            // 初始化下房间数据
            initPlaceData(placeData);
        }
    }

    private void initPlaceData(CrossFeastPvpPlaceData placeData) {
        int birthPoint = config.getFEAST_PVP_JOIN_CONDITION() / 2;
        if(birthPoint == 0){
            birthPoint = 10;
        }
        // 出生点角度
        double angle = 360.0 / birthPoint;
        double initAngle = 0;
        FeastPvpPlaceConfig feastPvpPlaceConfig = config.getPlaceConfigMap().get(placeData.getPlaceId());
        int radius = Math.min(feastPvpPlaceConfig.getMapSizeList().get(0) / 2, feastPvpPlaceConfig.getMapSizeList().get(1) / 2);
        //最大头像半径
        radius -= config.getMaxProfileRadius();
        List<FeastPvpBirthData> birthDataList = new ArrayList<>();
        for (int i = 0; i < birthPoint; i++) {
            // 将角度转换为弧度
            double rad = Math.toRadians(initAngle);
            // 计算圆上的点的坐标
            double xCoordinate = radius * Math.cos(rad);
            double yCoordinate = radius * Math.sin(rad);
            FeastPvpBirthData birthData = new FeastPvpBirthData();
            birthData.setRoomId(placeData.getPlaceId());
            birthData.setCoordinate(new Coordinate(calcX(xCoordinate, feastPvpPlaceConfig, config.getMaxProfileRadius()), calcY(yCoordinate, feastPvpPlaceConfig, config.getMaxProfileRadius())));
            birthData.setBirthCnt(0);
            birthDataList.add(birthData);
            initAngle += angle;
        }
        placeData.setBirthDataList(birthDataList);
    }

    /**
     * 锁定名单
     */
    public void crossFeastLockDataTask() {
        if (crossFeastPvpData.isLockState()) {
            return;
        }
        synchronized (lock) {
            if (crossFeastPvpData.isLockState()) {
                return;
            }

            // 没到锁定时间
            if (!isBattlePrepareTime() && !isBattleTime()) {
                return;
            }
            // 开始锁定
            int limit = config.getFEAST_PVP_JOIN_CONDITION();
            int rankNum = 0;
            for (CrossFeastRank rank : applyRankListModel.getRankList()) {
                if (rankNum >= limit) {
                    break;
                }
                long userId = Long.parseLong(rank.getId());
                CrossFeastPvpUserData userData = getPvpUserData(userId);
                if (userData == null || userData.getPveProperty().getPowerVal() <= 0) {
                    continue;
                }
                rankNum++;
                // 锁定时更新下属性
                updatePvpProperty(userData);
                // 锁定名单
                userData.setPvpAble(true);
                // 分配层级
                userData.setPlaceId(1);
                // 记录下报名日志
                CrossAutoLogMgr.add(new LogFeastPvpApply(
                        config.getActivityInfo().getActivityId(),
                        crossFeastPvpData.getRound(),
                        userId,
                        userData.getPvpProperty().getStateId(),
                        userData.getPvpProperty().getAbility(),
                        userData.isPvpAble(),
                        rankNum,
                        userData.getUpdatePropertyTime()
                ));

                FeastPvpPlaceConfig pvpPlaceConfig = config.getPlaceConfigMap().get(1);
                //出生点
                FeastPvpBirthData birthData = randomBirth(userData.getPlaceId());
                if (birthData != null) {
                    // 更新下位置
                    userData.getPosition().setX(calcX(birthData.getCoordinate().getX(), pvpPlaceConfig, userData.getProfileRadius()));
                    userData.getPosition().setY(calcY(birthData.getCoordinate().getY(), pvpPlaceConfig, userData.getProfileRadius()));
                    userData.getPosition().setDirX(0);
                    userData.getPosition().setDirY(0);
                    userData.getPosition().setTime(System.currentTimeMillis());
                }else {

                }
                addRoomUser(1, userId);

            }
            // 锁定状态
            crossFeastPvpData.setLockState(true);
        }
    }


    /**
     * 检测碰撞
     */
    public void checkBulletCollisionTask() {
        if (!isBattleTime() || crossFeastPvpData.isSettle() || !crossFeastPvpData.isLockState()) {
            return;
        }
        for (Integer roomId : pvpPlaceDataMap.keySet()) {
            // 获取房间内的玩家
            ConcurrentHashSet<Long> roomUserList = getRoomUserList(roomId);
            for (Long userId : roomUserList) {
                if(isRobot(userId)){
                    continue;
                }
                CrossFeastPvpUserData userData = getPvpUserData(userId);
                if (userData == null || !userData.isLive() || userData.getPlaceId() != roomId) {
                    continue;
                }
                if (!userData.isProtectTime()) {
                    // 检验玩家碰撞
                    checkPlayerCollision(userData);
                }
            }
        }
    }

    /**
     * 检验玩家碰撞
     *
     * @param userData
     */
    public void checkPlayerCollision(CrossFeastPvpUserData userData) {
        if (userData == null) {
            return;
        }
        int placeId = userData.getPlaceId();
        long nowTime = System.currentTimeMillis();

        // 攻速
        long atkSpeed = userData.getPvpProperty().getAttrMap().getOrDefault(eFeastType.BattleAttrType.AtkSpeed.getValue(), 1000L);
        // 攻速千分比 区间只能1-1000  程序做个保护
        int speedRatio = Math.max(1, Math.min(1000, config.getFEAST_PVP_ATTACK_SPEED_RATIO()));
        // 算下一秒攻击多少下  最低0.5,最大5下，特殊处理下 程序做个保护
        double atkCount = Math.min(5, Math.max(0.5, BigDecimal.valueOf(atkSpeed).divide(BigDecimal.valueOf(1000), 8, BigDecimal.ROUND_DOWN).multiply(BigDecimal.valueOf(speedRatio)).divide(BigDecimal.valueOf(1000), 8, BigDecimal.ROUND_DOWN).doubleValue()));
        // 攻击间隔
        long atkTime = BigDecimal.valueOf(1000).divide(BigDecimal.valueOf(atkCount), 0, BigDecimal.ROUND_UP).longValue();

        if(nowTime - userData.getAttackTime() < atkTime){
            return;
        }

        //可攻击范围内的玩家
        List<DistanceUser> distanceUserDataList = findDistanceUserData(userData, config.getFEAST_PVP_ATTACK_DISTANCE());
        if (distanceUserDataList.isEmpty()) {
            return;
        }
        DistanceUser attackTarget = null;
        ShanHeFeastProto.FeastAttackedUserSyncMsg.Builder syncAttackedUserBuilder;
        CrossFeastPvpAttackHelper attackHelper;

        synchronized (getPlaceLock(placeId)) {
            if(nowTime - userData.getAttackTime() < atkTime){
                return;
            }
            if(!userData.isLive() || userData.isProtectTime()){
                return;
            }
            DistanceUser first = null;
            DistanceUser second = null;
            for (DistanceUser distanceUser : distanceUserDataList) {
                if (distanceUser.getUserData() == null || !distanceUser.getUserData().canBattle() || distanceUser.getUserData().getPlaceId() != userData.getPlaceId()) {
                    continue;
                }
                if(first != null && second == null){
                    second = distanceUser;
                }
                if(first == null){
                    first = distanceUser;
                }
                if (userData.getLockTarget().getId() > 0) {
                    if (distanceUser.getUserData().getUserId() == userData.getLockTarget().getId() && distanceUser.getUserData().getReviveCnt() == userData.getLockTarget().getCtn()) {
                        attackTarget = distanceUser;
                        break;
                    }
                }
            }
            if (attackTarget == null) {
                if(first == null){
                    return;
                }
                attackTarget = first;
                if (second != null) {
                    if (second.getDistance() == attackTarget.getDistance() && second.getUserData().getPvpProperty().getHp() < attackTarget.getUserData().getPvpProperty().getHp()) {
                        attackTarget = second;
                    }
                }
            }

            attackHelper = attack(placeId, userData, attackTarget.getUserData());
            // 被打同步消息
            syncAttackedUserBuilder = syncAttackedUser(userData, attackTarget.getUserData(), attackHelper);

            if(attackHelper.getAttackedHp() == 0){
                attackHelper.setKillCnt(userData.getKillCnt() + 1);
                FeastPvpPlaceConfig pvpPlaceConfig = config.getPlaceConfigMap().get(placeId);
                if(pvpPlaceConfig.getUpDemand() > 0 && userData.getKillCnt() + 1 >= pvpPlaceConfig.getUpDemand()){
                    userData.setUpDemandTime(nowTime + DateHelper.SECOND_MILLIONS);
                    userData.setUpDownDemand(true);
                    //晋级，同步消息
//                    syncUpDownDemand(2, userData, placeId);
//                    if(Config.isDebug()) {
//                        CrossFeastMgr.getLogger().error("房间[{}], 玩家[{}],标记晋级", placeId, userData.getUserId());
//                    }
                    attackHelper.setUpGrade(true);
                }
            }

            // 记录一下攻击时间
            userData.setAttackTime(nowTime);
        }
        long attackScore = afterAttack(attackTarget.getUserData().getUserId(), nowTime, userData, attackHelper.getAttackedHp(), attackHelper, placeId);

        long attackedUserId = attackTarget.getUserData().getUserId();
        if(syncAttackedUserBuilder != null && !isRobot(attackedUserId) && !isNpc(attackedUserId)){
            sendPacket(ClientProtocol.U_SHAN_HE_FEAST_ATTACKED_USER_SYNC, syncAttackedUserBuilder, attackedUserId);
        }

        //击杀日志
        if(attackHelper.getAttackedHp() <= 0 && !isNpc(userData.getUserId())) {
            CrossAutoLogMgr.add(new LogFeastPvpKill(config.getActivityInfo().getActivityId(),
                    getCurRound(), userData.getUserId(), placeId, userData.getKillCnt(), userData.getReviveCnt(), userData.getPvpProperty().getAbility(), userData.getPvpProperty().getStateId(),
                    attackTarget.getUserData().getUserId(), attackTarget.getUserData().getPvpProperty().getAbility(), attackTarget.getUserData().getPvpProperty().getStateId(), attackScore));
        }
    }


    /**
     * 寻找距离小于xxx的玩家
     */
    public List<DistanceUser> findDistanceUserData(CrossFeastPvpUserData userData, double distance) {
        List<DistanceUser> list = new ArrayList<>();
        if (userData == null) {
            return list;
        }
        ConcurrentHashSet<Long> roomUserList = getRoomUserList(userData.getPlaceId());
        for (Long userId : roomUserList) {
            if (userData.getUserId() == userId) {
                continue;
            }
            CrossFeastPvpUserData targetUserData = getPvpUserData(userId);
            if (targetUserData == null || targetUserData.getPlaceId() != userData.getPlaceId() || targetUserData.isProtectTime() || !targetUserData.isLive()) {
                continue;
            }
            double d = distance(userData.getCoordinate(), targetUserData.getCoordinate());
            if (d <= distance + getProfileRadius(userData, false) + getProfileRadius(targetUserData, false)) {
                list.add(new DistanceUser(d, targetUserData));
            }
        }
        list.sort(Comparator.comparingDouble(DistanceUser::getDistance));
        return list;
    }

    /**
     * 重置用户数据
     */
    public void resetUserData(){
        for (CrossFeastPvpUserData userData : pvpUserDataMap.values()) {
            // 重置房间位置
            userData.setPlaceId(0);
            userData.setBattleRecord(new CrossFeastPvpBattleRecord());

            //本层
            userData.setReviveCnt(0);
            userData.setKillCnt(0);
            userData.setLockTarget(CrossFeastPvpLockTarget.EMPTY);

            userData.setUpDownDemand(false);
            userData.setUpDemandTime(0);
            userData.setDownDemandTime(0);

            userData.getEnterPlaceList().clear();

            // 资格重置下
            userData.setPvpAble(false);
            userData.setApply(false);

        }
    }


    /**
     * 同步房间内的用户数据
     */
    public void syncPlaceUserData() {
        if (!isActivityOpenTime()) {
            return;
        }
        List<CrossFeastPvpPlaceData> list = new ArrayList<>(pvpPlaceDataMap.values());
        for (CrossFeastPvpPlaceData placeData : list) {
            if (placeData.getPlaceId() == 0) {
                continue;
            }
            Set<Long> userList = getRoomUserList(placeData.getPlaceId());
            if (userList.size() == 0) {
                // 没有用户就不需要同步了
                continue;
            }
            // 同步用户给房间内的用户
            ShanHeFeastProto.FeastPlaceSyncMsg.Builder builder = ShanHeFeastProto.FeastPlaceSyncMsg.newBuilder();
            for (Long userId : userList) {
                CrossFeastPvpUserData pvpUserData = getPvpUserData(userId);
                if (pvpUserData == null || pvpUserData.getPlaceId() == 0) {
                    continue;
                }
                if (pvpUserData.getUserState() == 1) {
                    continue;
                }
                ShanHeFeastProto.FeastPvpSimpleUserTemp.Builder userTemp = ShanHeFeastProto.FeastPvpSimpleUserTemp.newBuilder();
                userTemp.setUserId(userId);
                userTemp.setPosition(parseFeastPvpPositionTemp(pvpUserData.getPosition()));
                builder.addUser(userTemp);
            }
//            sendPacketToAll(ClientProtocol.U_SHAN_HE_FEAST_PLACE_SYNC, builder, userList);
        }
    }

    public CrossFeastPvpCampData getPvpCampData(int campId) {
//        return pvpCampDataMap.get(campId);
        return null;
    }

    /**
     * 是否有资格
     */
    public boolean isAble(long userId) {
        if (isNpc(userId)) {
            return true;
        }
        CrossFeastPvpUserData userData = getPvpUserData(userId);
        return userData != null && userData.isPvpAble();
    }

    /**
     * 玩家进入pvp请求数据
     *
     * @param userId 玩家id
     */
    public int enterPvpByCmd(long userId) {
        // 判断下资格
        if (!crossFeastPvpData.isLockState()) {
            return GameErrorCode.E_SHAN_HE_FEAST_PVP_IN_LOCK_STATE;
        }
        ShanHeFeastProto.FeastEnterPvpRespMsg.Builder builder = ShanHeFeastProto.FeastEnterPvpRespMsg.newBuilder();
        builder.setRet(0);
        boolean able = isAble(userId);
        builder.setAble(able);
        if (!able) {
            // 没资格就返回
            sendPacket(ClientProtocol.U_SHAN_HE_FEAST_ENTER_PVP, builder, userId);
            return 0;
        }
        CrossFeastPvpUserData userData = getPvpUserData(userId);
        if (userData == null) {
            // 没数据也返回
            sendPacket(ClientProtocol.U_SHAN_HE_FEAST_ENTER_PVP, builder, userId);
            return 0;
        }
        inPvpActivity.add(userId);
        userData.setLockTarget(CrossFeastPvpLockTarget.EMPTY);
        // 用户数据
        builder.setPvpUserData(parseFeastPvpUserDataTemp(userData));
        // 房间信息
        ShanHeFeastProto.FeastPvpPlaceInfoTemp.Builder placeInfoTemp = parseFeastPvpPlaceInfoTemp(getPvpPlace(userData.getPlaceId()), userId);
        if (placeInfoTemp != null) {
            builder.setPlace(placeInfoTemp);
        }

        // 公告信息
        ShanHeFeastProto.FeastNoticeListMsg.Builder noticeList = ShanHeFeastProto.FeastNoticeListMsg.newBuilder();
        // 全服公告
        for (CrossFeastPvpNoticeData noticeData : noticeDataList) {
            ShanHeFeastProto.FeastNoticeTemp.Builder noticeTemp = parseFeastNoticeTemp(noticeData);
            if (noticeTemp != null) {
                noticeList.addNotice(noticeTemp);
            }
        }
        builder.setNoticeList(noticeList);
        sendPacket(ClientProtocol.U_SHAN_HE_FEAST_ENTER_PVP, builder, userId);

//        if(Config.isDebug() && noticeList.getNoticeCount() == 0){
//            CrossFeastMgr.getLogger().error("进入活动，房间{}， 玩家{}，位置 x {}, y {}, 没有公告", userData.getPlaceId(), userData.getUserId(), userData.getPosition().getX(), userData.getPosition().getY());
//        }
//        for (ShanHeFeastProto.FeastPvpOtherUserTemp temp : builder.getPlace().getUserList()) {
//            CrossFeastMgr.getLogger().error("进入活动，玩家{}，位置 x {}, y {}", temp.getPlayerData().getUserId(), temp.getPosition().getX(), temp.getPosition().getY());
//        }

        // 同步下积分
//        ShanHeFeastProto.FeastUserScoreSyncMsg.Builder userScoreBuilder = ShanHeFeastProto.FeastUserScoreSyncMsg.newBuilder();

//        int num = 3;
//        boolean containSelf = false;
//        for (CrossFeastRank crossFeastRank : battleRankListModel.getRankList()) {
//            ShanHeFeastProto.FeastUserScoreSyncTemp.Builder tempBuild = ShanHeFeastProto.FeastUserScoreSyncTemp.newBuilder();
//            tempBuild.setUserId()
//            userScoreBuilder.addUserScore(tempBuild);
//        }
//        List<ShanHeFeastProto.FeastUserScoreSyncTemp.Builder> list = FeastUserScoreSyncTemp();
//        for (ShanHeFeastProto.FeastCampScoreSyncTemp.Builder temp : list) {
//            campScoreBuilder.addCampScore(temp);
//        }
//        sendPacket(Protocol.U_SHAN_HE_FEAST_CAMP_SCORE_SYNC, campScoreBuilder, userId);

        return 0;
    }

    private ShanHeFeastProto.FeastNoticeTemp.Builder parseFeastNoticeTemp(CrossFeastPvpNoticeData noticeData) {
        if (noticeData == null) {
            return null;
        }
        ShanHeFeastProto.FeastNoticeTemp.Builder builder = ShanHeFeastProto.FeastNoticeTemp.newBuilder();
        CrossFeastPvpNoticeUserData user1 = noticeData.getUser1();
        if (user1.getUserId() != 0) {
            ShanHeFeastProto.FeastNoticeUserTemp.Builder user1Temp = ShanHeFeastProto.FeastNoticeUserTemp.newBuilder();
            user1Temp.setServerId(user1.getServerId());
            user1Temp.setNickName(user1.getNickName());
            user1Temp.setDecoration(user1.getDecoration());
            user1Temp.setStateId(user1.getStateId());
            builder.setUser1(user1Temp);
        }
        CrossFeastPvpNoticeUserData user2 = noticeData.getUser2();
        if (user2.getUserId() != 0) {
            ShanHeFeastProto.FeastNoticeUserTemp.Builder user2Temp = ShanHeFeastProto.FeastNoticeUserTemp.newBuilder();
            user2Temp.setServerId(user2.getServerId());
            user2Temp.setNickName(user2.getNickName());
            user2Temp.setDecoration(user2.getDecoration());
            user2Temp.setStateId(user2.getStateId());
            builder.setUser2(user2Temp);
        }
//        if (userId != 0) {
//            if (isNpc(userId)) {
//                CrossFeastNpcDataHelper dataHelper = npcDataMap.get(userId);
//                builder.setNickName(dataHelper.getNickName());
//                builder.setServerId(dataHelper.getServerId());
//            } else {
//                CrossUserBaseInfo userBaseInfo = CrossUserMgr.getCrossUserBaseInfo(userId);
//                if (userBaseInfo != null) {
//                    builder.setNickName(userBaseInfo.getUserBaseInfo().getNickName());
//                    builder.setServerId(userBaseInfo.getUserBaseInfo().getServerId());
//                }
//            }
//        }
        builder.setNoticeType(noticeData.getNoticeType());
        builder.setContent(noticeData.getContent());
        builder.setNoticeTime(noticeData.getNoticeTime());
        builder.setIsRoll(noticeData.getIsRoll());
        return builder;
    }

    /**
     * 离开pvp
     */
    public int leavePvpByCmd(long userId) {
        inPvpActivity.remove(userId);
//        CrossFeastPvpUserData userData = getPvpUserData(userId);
//        if (userData != null) {
//            // 如果在房间状态，则退出房间
//            leavePlace(userData, 1);
        ShanHeFeastProto.FeastLeavePvpRespMsg.Builder builder = ShanHeFeastProto.FeastLeavePvpRespMsg.newBuilder();
        builder.setRet(0);
        sendPacket(ClientProtocol.U_SHAN_HE_FEAST_LEAVE_PVP, builder, userId);
//        }
        return 0;
    }

    /**
     * 离线处理
     */
    public void offLineByCmd(long userId) {
        // 历练界面离线去除
//        leavePracticeByCmd(userId);
        // 离开pvp
        leavePvpByCmd(userId);
        // 离线离开灵峰房间
//        checkRoomOutPlayers(userId);
    }

    public int getActivityData(long userId) {
        // 回游戏服
        ShanHeFeastProto.CrossFeastPvpActivityDataSync.Builder builder = ShanHeFeastProto.CrossFeastPvpActivityDataSync.newBuilder();
        builder.setActivityId(config.getActivityInfo().getActivityId());
        builder.setRound(getCurRound());
        builder.setState(isBattleEndTime() ? 1 : 0);
        sendPacket(GameProtocol.S_CROSS_SHAN_HE_FEAST_GET_ACTIVITY_DATA, builder, userId);

        //登录同步下成就
        CrossFeastPvpUserData pvpUserData = getPvpUserData(userId);
        if(pvpUserData != null){
            for (Map.Entry<Integer, CrossFeastPvpBattleRecord> entry : pvpUserData.getRoundBattleRecordMap().entrySet()) {
                CrossFeastPvpBattleRecord value = entry.getValue();
                if(value.getTotalScore() > 0){
                    notifyConditionChange(pvpUserData.getUserId(), eGamePlayerEventType.FeastPersonalScore, value.getTotalScore(), entry.getKey());
                }
            }
        }
        return 0;
    }

    /**
     * 获取PVP结束信息
     */
    public int getPvpEndData(long serverId, long userId, int endRound) {
        CrossFeastPvpUserData userData = getPvpUserData(userId);
        if (userData == null) {
            return GameErrorCode.E_SHAN_HE_FEAST_PVP_USER_NOT_FOUND;
        }

        CrossFeastRankListModel listModel = roundRankListModel.get(endRound);
        if(listModel != null){
            int rankNum = 0;
            List<ShanHeFeastProto.FeastRankTempMsg> list = new ArrayList<>();
            for (CrossFeastRank rank : listModel.getRankList()) {
                rankNum++;
                CrossFeastPvpUserData pvpUserData = getPvpUserData(Long.valueOf(rank.getId()));
                if (pvpUserData == null) {
                    continue;
                }
                ShanHeFeastProto.FeastRankTempMsg.Builder rankBuilder = ShanHeFeastProto.FeastRankTempMsg.newBuilder();
                rankBuilder.setValue(String.valueOf(rank.getValue()));
                rankBuilder.setParam(rank.getParam());
                rankBuilder.setUserId(Long.valueOf(rank.getId()));
                UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(rankBuilder.getUserId());
                if (userBaseInfo != null) {
                    rankBuilder.setPlayerBaseData(PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo));
                    list.add(rankBuilder.build());
                }
                if(rankNum >= super.userMaxRankConfig){
                    break;
                }
            }
            ShanHeFeastProto.FeastSettleSyncMsg.Builder syncMsg = getEndBuilder(list, endRound, listModel, userId);
            MessageHelper.sendPacket(serverId, userId, YanQuMessageUtils.buildMessage(Protocol.U_SHAN_HE_FEAST_GET_PVP_END_DATA,
                    ShanHeFeastProto.FeastPvpEndDataRespMsg.newBuilder().setRet(0).setEndData(syncMsg)));
        }else {
            MessageHelper.sendPacket(serverId, userId, YanQuMessageUtils.buildMessage(Protocol.U_SHAN_HE_FEAST_GET_PVP_END_DATA,
                    ShanHeFeastProto.FeastPvpEndDataRespMsg.newBuilder().setRet(0)));
        }
        return 0;
    }


    /**
     * 获取榜单积分详情
     */
    public int getScoreRankDetail(long userId, long targetUserId) {
        CrossFeastPvpUserData targetUserData = getPvpUserData(targetUserId);
        if (targetUserData == null) {
            return GameErrorCode.E_SHAN_HE_FEAST_PVP_USER_DATA_NOT_FOUND;
        }
        ShanHeFeastProto.FeastPvpScoreRankDetailRespMsg.Builder respMsg = ShanHeFeastProto.FeastPvpScoreRankDetailRespMsg.newBuilder();
        int round = getCurRound();
        int days = DateHelper.calc2DateTDOADays(new Date(config.getActivityInfo().getBeginTime() * 1000), new Date(config.getActivityInfo().getEndTime() * 1000));
        if(round > days){
            round = days;
        }
        for (int i = 1; i <= round; i++) {
            CrossFeastPvpBattleRecord battleRecord = targetUserData.getRoundBattleRecordMap().get(i);
            if(battleRecord == null){
                ShanHeFeastProto.FeastPvpScoreRankDetailTemp.Builder temp = ShanHeFeastProto.FeastPvpScoreRankDetailTemp.newBuilder();
                temp.setRound(i);
                temp.setRank(-1);
                temp.setKillCnt(0);
                temp.setScore(0);
                temp.setSeizeScore(0);
                respMsg.addDetail(temp);
            }else {
                ShanHeFeastProto.FeastPvpScoreRankDetailTemp.Builder temp = ShanHeFeastProto.FeastPvpScoreRankDetailTemp.newBuilder();
                temp.setRound(i);
                temp.setRank(-1);
                temp.setKillCnt(battleRecord.getKill());
                temp.setScore(battleRecord.getKillScore());
                temp.setSeizeScore(battleRecord.getSeizeScore());
                respMsg.addDetail(temp);
            }
        }
        respMsg.setRet(0);
        sendPacket(Protocol.U_SHAN_HE_FEAST_PVP_GET_SCORE_RANK_DETAIL, respMsg, userId);
        return 0;
    }

    /**
     * 移动
     *
     * @param userId   玩家id
     * @param position 位置信息
     */
    public int moveByCmd(long userId, CrossFeastPvpPosition position) {
        if (!isAble(userId)) {
            return GameErrorCode.E_SHAN_HE_FEAST_PVP_NO_ABLE;
        }
        CrossFeastPvpUserData pvpUserData = getPvpUserData(userId);
        if (pvpUserData == null) {
            return GameErrorCode.E_SHAN_HE_FEAST_PVP_USER_NOT_FOUND;
        }
        if (!pvpUserData.canMoveAble()){
            return GameErrorCode.E_SHAN_HE_FEAST_PVP_DIE;
        }
        // 移动
        position.setX(position.getX() / 10000);
        position.setY(position.getY() / 10000);
        position.setDirX(position.getDirX() / 10000);
        position.setDirY(position.getDirY() / 10000);
        playerMoveHandler(pvpUserData, position, true);
        ShanHeFeastProto.FeastMoveRespMsg.Builder builder = ShanHeFeastProto.FeastMoveRespMsg.newBuilder();
        builder.setRet(0);
        sendPacket(ClientProtocol.U_SHAN_HE_FEAST_MOVE, builder, userId);
        return 0;
    }

    /**
     * 传送
     * @param playerId   玩家id
     * @param position 位置信息
     */
    public int jumpByCmd(long serverId, long playerId, CrossFeastPvpPosition position) {
        if (!isAble(playerId)) {
            return GameErrorCode.E_SHAN_HE_FEAST_PVP_NO_ABLE;
        }
        CrossFeastPvpUserData pvpUserData = getPvpUserData(playerId);
        if (pvpUserData == null) {
            return GameErrorCode.E_SHAN_HE_FEAST_PVP_USER_NOT_FOUND;
        }
        if (!pvpUserData.canMoveAble()){
            return GameErrorCode.E_SHAN_HE_FEAST_PVP_DIE;
        }
        long nowTime = System.currentTimeMillis();
        if(nowTime < pvpUserData.getTransferTime()){
            return GameErrorCode.E_SHAN_HE_FEAST_PVP_DONT_TRANSFER;
        }
        pvpUserData.setTransferTime(nowTime + config.getFEAST_PVP_TP_CD() * DateHelper.SECOND_MILLIONS);
        int placeId = pvpUserData.getPlaceId();

        //传送距离判断

        // 移动
        position.setX(position.getX() / 10000);
        position.setY(position.getY() / 10000);
        position.setDirX(position.getDirX() / 10000);
        position.setDirY(position.getDirY() / 10000);
        playerMoveHandler(pvpUserData, position, false);

        ShanHeFeastProto.FeastPositionJumpRespMsg.Builder builder = ShanHeFeastProto.FeastPositionJumpRespMsg.newBuilder();
        builder.setRet(0);
        MessageHelper.sendPacket(serverId, playerId, YanQuMessageUtils.buildMessage(Protocol.U_SHAN_HE_FEAST_JUMP, builder));

        //同步下房间操作
        ShanHeFeastProto.FeastPlaceOptTemp.Builder optBuilder = ShanHeFeastProto.FeastPlaceOptTemp.newBuilder();
        optBuilder.setType(2);
        optBuilder.setUserId(playerId);
        optBuilder.setOptTime(nowTime);
        optBuilder.setParam(String.valueOf(pvpUserData.getPosition().getX() * 10000));
        optBuilder.setParam2(String.valueOf(pvpUserData.getPosition().getY() * 10000));
        addPvpOptSyncData(placeId, optBuilder.build());
        return 0;
    }

    /**
     * 锁定玩家
     */
    public int lockUserByCmd(long serverId, long playerId, long userId){
        if (!isAble(playerId)) {
            return GameErrorCode.E_SHAN_HE_FEAST_PVP_NO_ABLE;
        }
        CrossFeastPvpUserData pvpUserData = getPvpUserData(playerId);
        if (pvpUserData == null) {
            return GameErrorCode.E_SHAN_HE_FEAST_PVP_USER_NOT_FOUND;
        }

        if(userId == 0){
            pvpUserData.setLockTarget(CrossFeastPvpLockTarget.EMPTY);
        }else {
            CrossFeastPvpUserData targetUser = getPvpUserData(userId);
            if (targetUser == null || !targetUser.isPvpAble()) {
                return GameErrorCode.E_SHAN_HE_FEAST_PVP_USER_NOT_FOUND;
            }
            pvpUserData.setLockTarget(new CrossFeastPvpLockTarget(targetUser.getUserId(), targetUser.getReviveCnt()));
        }
        ShanHeFeastProto.FeastLockTargetRespMsg.Builder clientMsg = ShanHeFeastProto.FeastLockTargetRespMsg.newBuilder();
        clientMsg.setRet(0);
        MessageHelper.sendPacket(serverId, playerId, YanQuMessageUtils.buildMessage(Protocol.U_SHAN_HE_FEAST_LOCK_TARGET, clientMsg));
        return 0;
    }

    /**
     * 加速
     */
    public int speedUpByCmd(long serverId, long playerId){
        if (!isAble(playerId)) {
            return GameErrorCode.E_SHAN_HE_FEAST_PVP_NO_ABLE;
        }
        CrossFeastPvpUserData pvpUserData = getPvpUserData(playerId);
        if (pvpUserData == null) {
            return GameErrorCode.E_SHAN_HE_FEAST_PVP_USER_NOT_FOUND;
        }
        long nowTime = System.currentTimeMillis();
        if(pvpUserData.getLastSpeedTime() > nowTime){
            //cd 未到
            return GameErrorCode.E_SHAN_HE_FEAST_PVP_DONT_SPEED_UP;
        }
        pvpUserData.setLastSpeedTime(nowTime + config.getFEAST_PVP_HASTEN_CD() * DateHelper.SECOND_MILLIONS);

        long continueTime = config.getFEAST_PVP_HASTEN_TIME() * DateHelper.SECOND_MILLIONS;
        pvpUserData.setSpeedEndTime(nowTime + continueTime);
        int placeId = pvpUserData.getPlaceId();

        ShanHeFeastProto.FeastSpeedUpRespMsg.Builder clientMsg = ShanHeFeastProto.FeastSpeedUpRespMsg.newBuilder();
        clientMsg.setRet(0);
        MessageHelper.sendPacket(serverId, playerId, YanQuMessageUtils.buildMessage(Protocol.U_SHAN_HE_FEAST_SPEED_UP, clientMsg));

        //同步操作
        ShanHeFeastProto.FeastPlaceOptTemp.Builder optBuilder = ShanHeFeastProto.FeastPlaceOptTemp.newBuilder();
        optBuilder.setType(1);
        optBuilder.setUserId(playerId);
        optBuilder.setOptTime(nowTime);
        optBuilder.setParam(String.valueOf(pvpUserData.getSpeedEndTime()));
        addPvpOptSyncData(placeId, optBuilder.build());
        return 0;
    }

    /**
     * 心跳
     */
    public int pingByCmd(long userId, int type) {
        if ((!isBattleTime() && !isBattlePrepareTime()) || crossFeastPvpData.isSettle()) {
            return GameErrorCode.E_SHAN_HE_FEAST_PVP_NOT_BATTLE_TIME;
        }
        CrossFeastPvpUserData userData = getPvpUserData(userId);
        if (userData == null) {
            return GameErrorCode.E_SHAN_HE_FEAST_PVP_USER_DATA_NOT_FOUND;
        }
        if (type == 0) {
            // 更新心跳时间
            userData.setLastPingPlaceTime(System.currentTimeMillis());
            // 检测buff变动
//            if (userData.getProperty().checkBuff()) {
//                // 重新计算战斗属性
//                changeAttributeMap(userData);
//            }
        } else if (type == 1) {
            // 离开房间，不参与同步,心跳时间改掉
            userData.setLastPingPlaceTime(-1);
            inPvpActivity.remove(userId);
        }

        return 0;
    }

    /**
     * 攻击
     */
    public int attackByCmd(long userId, long attackedUserId) {
        if (!isAble(userId) || !isAble(attackedUserId)) {
            return GameErrorCode.E_SHAN_HE_FEAST_PVP_NO_ABLE;
        }
        long nowTime = System.currentTimeMillis();
        CrossFeastPvpUserData userData;
        // 获取被攻击人的信息
        long leftHp;
        int stageId;
        CrossFeastPvpAttackHelper attackHelper;
        int placeId;
        userData = getPvpUserData(userId);
        if (userData == null) {
            return GameErrorCode.E_SHAN_HE_FEAST_PVP_USER_NOT_FOUND;
        }
        if (userData.getUserState() == 1) {
            return GameErrorCode.E_SHAN_HE_FEAST_PVP_DIE;
        }
        // 攻速
        long atkSpeed = userData.getPvpProperty().getAttrMap().getOrDefault(eFeastType.BattleAttrType.AtkSpeed.getValue(), 1000L);
        // 攻速千分比 区间只能1-1000  程序做个保护
        int speedRatio = Math.max(1, Math.min(1000, config.getFEAST_PVP_ATTACK_SPEED_RATIO()));
        // 算下一秒攻击多少下  最低0.5,最大5下，特殊处理下 程序做个保护
        double atkCount = Math.min(5, Math.max(0.5, BigDecimal.valueOf(atkSpeed).divide(BigDecimal.valueOf(1000), 8, BigDecimal.ROUND_DOWN).multiply(BigDecimal.valueOf(speedRatio)).divide(BigDecimal.valueOf(1000), 8, BigDecimal.ROUND_DOWN).doubleValue()));
        // 攻击间隔
        long atkTime = BigDecimal.valueOf(1000).divide(BigDecimal.valueOf(atkCount), 0, BigDecimal.ROUND_UP).longValue();
        if (nowTime - userData.getAttackTime() < atkTime) {
            return GameErrorCode.E_SHAN_HE_FEAST_ATTACK_TIME_LIMIT;
        }
        placeId = userData.getPlaceId();
        CrossFeastPvpUserData attackedUserData;
        // 打架获取房间锁
        synchronized (getPlaceLock(placeId)) {
            // 被攻击者
            attackedUserData = getPvpUserData(attackedUserId);
            if (attackedUserData == null) {
                return GameErrorCode.E_SHAN_HE_FEAST_PVP_USER_NOT_FOUND;
            }
            FeastPvpUserProperty attackedProperty = attackedUserData.getPvpProperty();
            // 判断是否能攻击
            if (attackedProperty.getHp() == 0) {
                return GameErrorCode.E_SHAN_HE_FEAST_TARGET_NOT_FOUND;
            }
            if (attackedUserData.getPlaceId() != placeId) {
                return GameErrorCode.E_SHAN_HE_FEAST_TARGET_NOT_FOUND;
            }
            stageId = attackedProperty.getStateId();
            // 攻击
            attackHelper = attack(placeId, userData, attackedUserData);
            // 被打同步消息
            syncAttackedUser(userData, attackedUserData, attackHelper);
            // 记录一下攻击时间
            userData.setAttackTime(nowTime);
            leftHp = attackHelper.getAttackedHp();
        }

        long attackScore = afterAttack(attackedUserId, nowTime, userData, leftHp, attackHelper, placeId);

        ShanHeFeastProto.FeastAttackRespMsg.Builder builder = ShanHeFeastProto.FeastAttackRespMsg.newBuilder();
        builder.setRet(0);
        builder.setAttackTime(nowTime);
        builder.setAttack(parseFeastAttackedTemp(attackHelper));
        builder.setAttackScore(attackScore);

        //击杀日志
        if(leftHp <= 0) {
            CrossAutoLogMgr.add(new LogFeastPvpKill(config.getActivityInfo().getActivityId(),
                    getCurRound(), userId, placeId, userData.getKillCnt(), userData.getReviveCnt(), userData.getPvpProperty().getAbility(), userData.getPvpProperty().getStateId(),
                        attackedUserId, attackedUserData.getPvpProperty().getAbility(), attackedUserData.getPvpProperty().getStateId(), attackScore));
        }

        return 0;
    }

    private long afterAttack(long attackedUserId, long nowTime, CrossFeastPvpUserData userData, long leftHp, CrossFeastPvpAttackHelper attackHelper, int placeId) {
        long attackScore = 0;
        // 成功击杀
        if (leftHp == 0) {
            // 成功击杀同步房间被打记录
            syncPlaceAttack(placeId);

            int curRound = getCurRound();

            FeastPvpPlaceConfig pvpPlaceConfig = config.getPlaceConfigMap().get(placeId);

            CrossFeastPvpUserData attackedUser = getPvpUserData(attackedUserId);
            FeastStateConfig stateConfig = config.getStateConfigMap().get(attackedUser.getPvpProperty().getStateId());

            attackScore = BigDecimal.valueOf(stateConfig.getPvpScore()).multiply(BigDecimal.valueOf(pvpPlaceConfig.getSkillScore())).divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP).intValue();


            if(attackHelper.isUpGrade()) {

                boolean first = false;
                CrossFeastPvpPlaceData placeData = pvpPlaceDataMap.get(placeId + 1);
                if(!isNpc(userData.getUserId())) {
                    synchronized (getPlaceLock(placeData.getPlaceId())) {
                        if (placeData.getFirstUser() == 0) {
                            first = true;
                            placeData.setFirstUser(userData.getUserId());
                            placeData.setUpdateTime(nowTime);
                        }
                    }
                }

                //晋级积分
                int firstUpScore = 0;
                synchronized (getPlayerLock(userData.getUserId())) {
                    if (!userData.getEnterPlaceList().contains(placeId + 1)) {
                        //晋级积分加到楼层得分
                        firstUpScore = config.getPlaceConfigMap().get(placeId + 1).getFirstUpScore();
                        addBattleScore(userData.getUserId(), 3, firstUpScore, "");
                        userData.getEnterPlaceList().add(placeId + 1);
                    }
                }

                syncUpDownDemand(2, userData, placeId, firstUpScore > 0);


                if (first) {
                    //该层首次晋级公告
                    CrossFeastPvpNoticeData noticeData = new CrossFeastPvpNoticeData();
                    noticeData.setUserId(userData.getUserId());
                    noticeData.setActivityId(config.getActivityInfo().getActivityId());
                    noticeData.setRound(curRound);
                    noticeData.setNoticeType(eFeastPvpNoticeType.FirstEntry.getValue());
                    noticeData.setContent(String.valueOf(placeData.getPlaceId()));
                    noticeData.setNoticeTime(nowTime);
                    noticeData.setIsRoll(1);
                    addPvpNoticeData(noticeData, userData.getUserId(), 0);
                }
            }

            // 记录战绩
            addBattleScore(userData.getUserId(), 1, attackScore, String.valueOf(attackedUserId));

            if(isNpc(userData.getUserId())){
                return attackScore;
            }

            // 单条命击杀公告
            List<String> noticeParamList = StringUtils.stringToStringList(config.getFEAST_PVP_NOTICE_SINGLE_TIME_KILL_NUM(), "\\|");
            int noticeState = Integer.parseInt(noticeParamList.get(0));
//            if(noticeState == 1){
                String params = noticeParamList.get(1);
                List<Integer> paramList = StringUtils.stringToIntegerList(params, ";");
                int killNum = userData.getBattleRecord().getKill();
                if (paramList.contains(killNum)) {
                    // 添加单条命击杀公告
                    CrossFeastPvpNoticeData noticeData = new CrossFeastPvpNoticeData();
                    noticeData.setActivityId(config.getActivityInfo().getActivityId());
                    noticeData.setRound(curRound);
                    noticeData.setNoticeType(eFeastPvpNoticeType.Kill.getValue());
                    noticeData.setContent(String.valueOf(killNum));
                    noticeData.setNoticeTime(nowTime);
                    noticeData.setIsRoll(Integer.parseInt(noticeParamList.get(0)));
                    addPvpNoticeData(noticeData, userData.getUserId(), 0);
                }
//            }
            // 单轮击杀公告
            List<String> noticeParamList1 = StringUtils.stringToStringList(config.getFEAST_PVP_NOTICE_SINGLE_WHEEL_KILL_NUM(), "\\|");
            noticeState = Integer.parseInt(noticeParamList1.get(0));
//            if(noticeState == 1){
                String params1 = noticeParamList1.get(1);
                List<Integer> paramList1 = StringUtils.stringToIntegerList(params1, ";");
                int roundKillNum = 0;
                if (userData.getRoundBattleRecordMap().containsKey(curRound)) {
                    roundKillNum = userData.getRoundBattleRecordMap().get(curRound).getKill();
                }
                if (paramList1.contains(roundKillNum)) {
                    // 添加本轮斗法累计击杀公告
                    CrossFeastPvpNoticeData noticeData = new CrossFeastPvpNoticeData();
                    noticeData.setActivityId(config.getActivityInfo().getActivityId());
                    noticeData.setRound(curRound);
                    noticeData.setNoticeType(eFeastPvpNoticeType.RoundKill.getValue());
                    noticeData.setContent(String.valueOf(roundKillNum));
                    noticeData.setNoticeTime(nowTime);
                    noticeData.setIsRoll(Integer.parseInt(noticeParamList1.get(0)));
                    addPvpNoticeData(noticeData, userData.getUserId(), 0);
                }
//            }
        }
        return attackScore;
    }

    private void syncUpDownDemand(int type, CrossFeastPvpUserData userData, int placeId, boolean firstUpgrade) {
        ShanHeFeastProto.FeastUpDownDemandTemp.Builder builder = ShanHeFeastProto.FeastUpDownDemandTemp.newBuilder();
        builder.setType(type);
        builder.setDownDemandTime(userData.getDownDemandTime());
        builder.setUpDemandTime(userData.getUpDemandTime());
        builder.setUser(parseFeastPvpPlayerSimpleTempMsg(userData));
        builder.setIsFirst(firstUpgrade);
        addPvpDemandSyncData(placeId, builder.build());
    }

    /**
     * 攻击
     *
     * @param placeId      房间id
     * @param attackUser   攻击者
     * @param attackedUser 被攻击者
     */
    public CrossFeastPvpAttackHelper attack(int placeId, CrossFeastPvpUserData attackUser, CrossFeastPvpUserData attackedUser) {
        // 添加攻击记录
        CrossFeastPvpAttackHelper attackHelper = new CrossFeastPvpAttackHelper();
        attackHelper.setAttackUserId(attackUser.getUserId());
        attackHelper.setAttackedUserId(attackedUser.getUserId());
        FeastPvpUserProperty attackedProperty = attackedUser.getPvpProperty();
        FeastPvpUserProperty attackProperty = attackUser.getPvpProperty();
        // 攻击逻辑
        // 先判断是否能闪避本次攻击
        // 闪避几率 = (对方闪避值千分数 - 我方命中值千分数) / 1000
        long dodgeValue = attackedProperty.getAttrMap().getOrDefault(eFeastType.BattleAttrType.DodgeRatio.getValue(), 0L) - attackProperty.getAttrMap().getOrDefault(eFeastType.BattleAttrType.HitRatio.getValue(), 0L);
        if(dodgeValue > config.getFEAST_MAX_SHANBI_SHANGXIAN()){
            dodgeValue = config.getFEAST_MAX_SHANBI_SHANGXIAN();
        }
        boolean isDodge = randomHelper.next(0, 1000) < Math.max(0, dodgeValue);
        if (!isDodge) {
            // 没闪避才继续往下处理
            // 暴击几率 = (我方暴击值千分数 - 对方坚韧值千分数) / 1000
            boolean isCrit = randomHelper.next(0, 1000) < Math.max(0, attackProperty.getAttrMap().getOrDefault(eFeastType.BattleAttrType.CritRatio.getValue(), 0L) - attackedProperty.getAttrMap().getOrDefault(eFeastType.BattleAttrType.TenacityRatio.getValue(), 0L));
            long attackHp = attackProperty.getAttrMap().getOrDefault(eFeastType.BattleAttrType.Atk.getValue(), 0L);
            if (isCrit) {
                attackHp *= 2;
            }
            attackHp = Math.min(attackHp, attackedProperty.getHp());
            // 扣血
            attackedProperty.setHp(attackedProperty.getHp() - attackHp);
            // 吸血
            long suckHp = Math.min(attackProperty.getAttrMap().getOrDefault(eFeastType.BattleAttrType.Hp.getValue(), 0L) - attackProperty.getHp(), BigDecimal.valueOf(attackHp).multiply(BigDecimal.valueOf(attackProperty.getAttrMap().getOrDefault(eFeastType.BattleAttrType.SuckRatio.getValue(), 0L))).divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_DOWN).longValue());
            // 加血
            attackProperty.setHp(attackProperty.getHp() + suckHp);
            attackHelper.setCrit(isCrit);
            attackHelper.setHp(attackHp);
            attackHelper.setSuckHp(suckHp);
        }
        attackUser.setPvpProperty(attackProperty);
        attackedUser.setPvpProperty(attackedProperty);
        attackHelper.setDodge(isDodge);
        attackHelper.setAttackHp(attackProperty.getHp());
        attackHelper.setAttackedHp(attackedProperty.getHp());
        addPvpAttackSyncData(placeId, attackHelper);
        return attackHelper;
    }

    public long calcTotalScore(CrossFeastPvpUserData userData) {
        if (userData == null) {
            return 0;
        }
        return userData.getAttackScore() + userData.getSeizeScore();
    }

    private boolean isNpc(long userId) {
        return npcUserMap.containsKey(userId) && npcDataMap.containsKey(userId);
    }

    //机器人
    private boolean isRobot(long userId) {
        return robotUserMap.containsKey(userId) || robotDataMap.containsKey(userId);
    }

    public void initRobot(){
        if(!isActivityOpenTime()){
            return;
        }
        if(!isBattleTime()){
            return;
        }
        if(!robotUserMap.isEmpty()){
            return;
        }
        long battleStartTime = getBattleStartTime();
        long nowTime = System.currentTimeMillis();
        if(nowTime < battleStartTime + config.getFEAST_ROBOT_APPEAR_TIME() * DateHelper.SECOND_MILLIONS){
            return;
        }
        for (int i = 0; i < config.getFEAST_ROBOT_NUM(); i++) {
            long id = robotId++;
            if (!robotUserMap.containsKey(id)) {
                CrossFeastPvpUserData robot = new CrossFeastPvpUserData();
                robot.setActivityId(config.getActivityInfo().getActivityId());
                robot.setUserId(id);
                // 出生地id
                robot.setPlaceId(1);
                // 可传送时间
                robot.setTransferTime(System.currentTimeMillis());
                // 可复活时间
                robot.setReviveTime(System.currentTimeMillis());
                // 生命标识
                robot.setReviveCnt(0);
                robot.setPvpAble(true);
                robot.setApply(true);
                // 造一份假属性
                FeastPveUserProperty pveProperty = robot.getPveProperty();
                Map<Integer, Long> attrMap = new HashMap<>();
                attrMap.putAll(config.getFEAST_ROBOT_PRIMARY_ATTRIBUTE());
                attrMap.putAll(config.getFEAST_ROBOT_SECONDARY_ATTRIBUTE());
                pveProperty.setAttrMap(attrMap);
                pveProperty.setPowerVal(0);
                pveProperty.setStateId(config.getFEAST_ROBOT_STATE_ID());
                robot.setPveProperty(pveProperty);
                updatePvpProperty(robot);
                robotUserMap.put(id, robot);

                //出生点
                FeastPvpBirthData birthData = randomBirth(robot.getPlaceId());
                FeastPvpPlaceConfig pvpPlaceConfig = config.getPlaceConfigMap().get(robot.getPlaceId());
                if (birthData != null && pvpPlaceConfig != null) {
                    // 更新下位置
                    robot.getPosition().setX(calcX(birthData.getCoordinate().getX(), pvpPlaceConfig, robot.getProfileRadius()));
                    robot.getPosition().setY(calcY(birthData.getCoordinate().getY(), pvpPlaceConfig, robot.getProfileRadius()));
                    robot.getPosition().setDirX(0);
                    robot.getPosition().setDirY(0);
                    robot.getPosition().setTime(System.currentTimeMillis());
                }

                // 顺便生成一下信息
                CrossFeastNpcDataHelper dataHelper = new CrossFeastNpcDataHelper();
                dataHelper.setUserId(id);
                List<Long> list = new ArrayList<>(config.getActivityInfo().getServerIdList());
                dataHelper.setServerId(list.get(randomHelper.next(0, list.size())));
                dataHelper.setNickName(config.getFEAST_ROBOT_NAME_ID());
                dataHelper.setDecoration(config.getFEAST_ROBOT_ICON_ID());
                robotDataMap.put(id, dataHelper);

                addRoomUser(1, id);
                sendJoinPositionSyncMsg(robot);
            }
        }
    }

    /**
     * 增加击杀战绩
     *
     * @param type 1 击杀战绩 2 挂机得分  3 首次晋级得分
     * @param param type 1 传被击杀者id
     */
    public void addBattleScore(long userId, int type, long addScore, String param) {
        if (isNpc(userId)) {
            // npc不推公告，不记录战绩了
            CrossFeastPvpUserData pvpUserData = getPvpUserData(userId);
            if(pvpUserData != null) {
                pvpUserData.setKillCnt(pvpUserData.getKillCnt() + 1);
            }
            return;
        }
        int curRound = getCurRound();
        // 获取可推送档次
        long canNoticeScoreLevel = -1;
        long oldTotalScore;
        long newTotalScore;
        long oldRoundScore;
        long newRoundScore;
        CrossFeastPvpUserData userData;
        synchronized (getPlayerLock(userId)) {
            long nowTime = System.currentTimeMillis();
            userData = getPvpUserData(userId);
            oldTotalScore = calcTotalScore(userData);

            // 本条命战绩
            CrossFeastPvpBattleRecord battleRecord = userData.getBattleRecord();

            Map<Integer, CrossFeastPvpBattleRecord> roundBattleRecordMap = userData.getRoundBattleRecordMap();
            if (!roundBattleRecordMap.containsKey(curRound)) {
                roundBattleRecordMap.put(curRound, new CrossFeastPvpBattleRecord());
            }

            // 本轮战绩
            CrossFeastPvpBattleRecord roundBattleRecord = roundBattleRecordMap.get(curRound);

            oldRoundScore = roundBattleRecord.getTotalScore();
            if (type == 1) {

                //当前层
                userData.setKillCnt(userData.getKillCnt() + 1);

                //本条命
                battleRecord.setKill(battleRecord.getKill() + 1);
                battleRecord.setKillScore(battleRecord.getKillScore() + addScore);

                //本轮
                roundBattleRecord.setKill(roundBattleRecord.getKill() + 1);
                roundBattleRecord.setKillScore(roundBattleRecord.getKillScore() + addScore);

                //总战绩
                userData.setAttackScore(userData.getAttackScore() + addScore);
                userData.setTotalKillCnt(userData.getTotalKillCnt() + 1);

            } else if (type == 2 || type == 3) {

                //本条命
                battleRecord.setSeizeScore(battleRecord.getSeizeScore() + addScore);

                //本轮
                roundBattleRecord.setSeizeScore(roundBattleRecord.getSeizeScore() + addScore);

                //总战绩
                userData.setSeizeScore(userData.getSeizeScore() + addScore);
            }
            roundBattleRecord.setUpdateTime(nowTime);
            userData.setUpdateScoreTime(nowTime);

            newTotalScore = calcTotalScore(userData);
            newRoundScore = roundBattleRecord.getTotalScore();
            CrossAutoLogMgr.add(new LogFeastAddScore(config.getActivityInfo().getActivityId(), curRound, userId, type, addScore, newTotalScore));
        }

        // 战绩榜
        if (!isNpc(userId) && newTotalScore > 0) {
            userScoreRank.rankChange(new CrossFeastRank(String.valueOf(userData.getUserId()), newTotalScore, userData.getUpdateScoreTime(), String.valueOf(userData.getTotalKillCnt())));

            CrossFeastRankListModel roundRankModel = getRoundRank(curRound);
            //轮此排行
            CrossFeastPvpBattleRecord roundBattleRecord = userData.getRoundBattleRecordMap().get(curRound);
            if(roundBattleRecord != null){
                roundRankModel.rankChange(new CrossFeastRank(String.valueOf(userId), roundBattleRecord.getTotalScore(), userData.getUpdateScoreTime(), String.valueOf(roundBattleRecord.getKill())));
            }

        }
        long nowTime = System.currentTimeMillis();
        if (type == 1) {
            // 击杀大佬公告
            List<String> noticeParamList = StringUtils.stringToStringList(config.getFEAST_PVP_NOTICE_SINGLE_PERSONAL_SCORE(), "\\|");
            int noticeState = Integer.parseInt(noticeParamList.get(0));
            int noticeStateId = Integer.parseInt(noticeParamList.get(1));
            // 境界是否包含
            CrossFeastPvpUserData attackedUserData = getPvpUserData(Long.parseLong(param));
            if (attackedUserData != null && attackedUserData.getPveProperty().getStateId() >= noticeStateId) {
                // 添加公告
                CrossFeastPvpNoticeData noticeData = new CrossFeastPvpNoticeData();
                noticeData.setActivityId(config.getActivityInfo().getActivityId());
                noticeData.setRound(curRound);
                noticeData.setNoticeType(eFeastPvpNoticeType.KillBoss.getValue());
                noticeData.setContent(addScore + "#" + attackedUserData.getPveProperty().getStateId());
                noticeData.setNoticeTime(nowTime);
                noticeData.setIsRoll(Integer.parseInt(noticeParamList.get(0)));

                addPvpNoticeData(noticeData, userData.getUserId(), attackedUserData.getUserId());
            }
        }
        if (!isNpc(userId)) {
            // 通知游戏服更新condition成就
            CrossFeastPvpBattleRecord roundBattleRecord = userData.getRoundBattleRecordMap().get(curRound);
            if(roundBattleRecord != null && !inPvpActivity.contains(userId)){
                notifyConditionChange(userData.getUserId(), eGamePlayerEventType.FeastPersonalScore, roundBattleRecord.getTotalScore(), getCurRound());
            }
        }

        // 个人战绩公告
        List<String> noticeParamList = StringUtils.stringToStringList(config.getFEAST_PVP_NOTICE_PERSONAL_SCORE(), "\\|");
        int noticeState = Integer.parseInt(noticeParamList.get(0));
//        if(noticeState == 1){
            String params = noticeParamList.get(1);
            List<Integer> paramList = StringUtils.stringToIntegerList(params, ";");
            for (int score : paramList) {
                if (score > oldRoundScore && score <= newRoundScore) {
                    canNoticeScoreLevel = score;
                }
            }
            if (canNoticeScoreLevel >= 0) {
                // 添加公告
                CrossFeastPvpNoticeData noticeData = new CrossFeastPvpNoticeData();
                noticeData.setActivityId(config.getActivityInfo().getActivityId());
                noticeData.setRound(curRound);
                noticeData.setNoticeType(eFeastPvpNoticeType.TotalScore.getValue());
                noticeData.setContent(String.valueOf(canNoticeScoreLevel));
                noticeData.setNoticeTime(nowTime);
                noticeData.setIsRoll(Integer.parseInt(noticeParamList.get(0)));
                addPvpNoticeData(noticeData, userData.getUserId(), 0);
            }
//        }
    }
    /**
     * 历练地图界面同步操作
     */
    public void syncPracticeMenuOp(int opType, long userId, CrossFeastPvpUserData userData) {
        if (practiceUserSet.size() == 0) {
            return;
        }
        UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(userId);
        if (null == userBaseInfo) {
            return;
        }
        // 同步给房间的用户
        ShanHeFeastProto.FeastPracticeMenuOpSyncMsg.Builder syncMsg = ShanHeFeastProto.FeastPracticeMenuOpSyncMsg.newBuilder();
        ShanHeFeastProto.FeastPracticeMenuOpInfoTemp.Builder tempMsg = ShanHeFeastProto.FeastPracticeMenuOpInfoTemp.newBuilder();
        tempMsg.setOpType(opType);
        tempMsg.setUserId(userId);
        if (opType == 1) {
            tempMsg.setUserInfo(CrossShanHeFeastPb.parsePveSampleTemp(userBaseInfo, userData));
        }
        syncMsg.addOpInfoList(tempMsg);
        sendPacketToAll(ClientProtocol.U_SHAN_HE_FEAST_PRACTICE_MENU_OP_SYNC, syncMsg, practiceUserSet);
    }

    /**
     * 进入历练地图
     *
     * @param userId 玩家id
     */
    public int enterPracticeByCmd(long userId) {
        CrossFeastPvpUserData userData = getPvpUserData(userId);
        if (userData == null) {
            return GameErrorCode.E_SHAN_HE_FEAST_PVP_USER_NOT_FOUND;
        }
        synchronized (practiceUserSet) {
            // 限制人数
            if (practiceUserSet.size() < config.getFEAST_PRACTICE_MENU_NUM() || practiceUserSet.contains(userId)) {
                // 同步玩家进入
                syncPracticeMenuOp(1, userId, userData);
                practiceUserSet.add(userId);
            }
        }
        // 返回给进入玩家
        ShanHeFeastProto.FeastEnterPracticeMenuRespMsg.Builder builder = ShanHeFeastProto.FeastEnterPracticeMenuRespMsg.newBuilder();
        builder.setRet(0);
        for (long tempUserId : practiceUserSet) {
            UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(tempUserId);
            CrossFeastPvpUserData otherUserData = getPvpUserData(tempUserId);
            if (null == userBaseInfo || null == otherUserData || tempUserId == userId) {
                continue;
            }
            builder.addOtherUserList(CrossShanHeFeastPb.parsePveSampleTemp(userBaseInfo, otherUserData));
        }
        sendPacket(ClientProtocol.U_SHAN_HE_FEAST_ENTER_PRACTICE_MENU, builder, userId);
        return 0;
    }

    /**
     * 离开历练地图
     *
     * @param userId 玩家id
     */
    public void leavePracticeByCmd(long userId) {
        boolean isInRoom = false;
        synchronized (practiceUserSet) {
            if (practiceUserSet.contains(userId)) {
                isInRoom = true;
                practiceUserSet.remove(userId);
            }
        }
        if (isInRoom) {
            // 同步玩家离开
            syncPracticeMenuOp(2, userId, null);
        }
        return;
    }

    private ShanHeFeastProto.FeastAttackedTemp.Builder parseFeastAttackedTemp(CrossFeastPvpAttackHelper attackHelper) {
        ShanHeFeastProto.FeastAttackedTemp.Builder builder = ShanHeFeastProto.FeastAttackedTemp.newBuilder();
        builder.setAttackUserId(attackHelper.getAttackUserId());
        builder.setAttackedUserId(attackHelper.getAttackedUserId());
        builder.setHp(attackHelper.getHp());
        builder.setSuckHp(attackHelper.getSuckHp());
        builder.setIsCrit(attackHelper.isCrit());
        builder.setIsDodge(attackHelper.isDodge());
        builder.setAttackHp(attackHelper.getAttackHp());
        builder.setAttackedHp(attackHelper.getAttackedHp());
        builder.setKillCnt(attackHelper.getKillCnt());
        builder.setReviveCnt(attackHelper.getReviveCnt());
        builder.setReviveTime(attackHelper.getReviveTime());
        return builder;
    }

    /**
     * 被打同步
     */
    private ShanHeFeastProto.FeastAttackedUserSyncMsg.Builder syncAttackedUser(CrossFeastPvpUserData attackUserData, CrossFeastPvpUserData attackedUserData, CrossFeastPvpAttackHelper attackHelper) {
        ShanHeFeastProto.FeastAttackedUserSyncMsg.Builder builder = ShanHeFeastProto.FeastAttackedUserSyncMsg.newBuilder();
        if (attackedUserData.getPvpProperty().getHp() <= 0) {
            attackHelper.setReviveCnt(attackedUserData.getReviveCnt() + 1);
            int placeId = attackedUserData.getPlaceId();
            FeastPvpPlaceConfig feastPvpPlaceConfig = config.getPlaceConfigMap().get(placeId);

            long nowTime = System.currentTimeMillis();

            // 复活时间
            int cd = getReviveCd(attackedUserData);
            attackedUserData.setReviveTime(nowTime + DateHelper.SECOND_MILLIONS * cd);
            attackHelper.setReviveTime(attackedUserData.getReviveTime());

            // 记录一下被打时间
            attackedUserData.setAttackedTime(nowTime);

            if(feastPvpPlaceConfig.getDownDemand() > 0 && attackedUserData.getReviveCnt() + 1 >= feastPvpPlaceConfig.getDownDemand()){
                attackedUserData.setUpDownDemand(true);
                attackedUserData.setDownDemandTime(nowTime + DateHelper.SECOND_MILLIONS);
                //降级，同步消息
                syncUpDownDemand(1, attackedUserData, placeId, false);
//                if(Config.isDebug()) {
//                    CrossFeastMgr.getLogger().error("房间[{}], 玩家[{}],被[{}]击杀,标记降级", placeId, attackedUserData.getUserId(), attackUserData.getUserId());
//                }
            }else {
//                if(Config.isDebug()) {
//                    CrossFeastMgr.getLogger().error("房间[{}], 玩家[{}],被[{}]击杀", placeId, attackedUserData.getUserId(), attackUserData.getUserId());
//                }
            }

            if (isNpc(attackedUserData.getUserId()) || isRobot(attackedUserData.getUserId())) {
                // npc不需要往下处理了
                return null;
            }
            // 本条命战绩
            CrossFeastPvpBattleRecord battleRecord = attackedUserData.getBattleRecord();
            builder.setBattleScore(parseFeastPvpBattleScoreTemp(battleRecord));
            // 本轮战绩
//            builder.setTotalBattleScore(parseFeastPvpBattleScoreTemp(attackedUserData.getRoundBattleRecord()));
            builder.setTotalBattleScore(parseFeastPvpBattleScoreTemp(attackedUserData.getRoundBattleRecordMap().get(getCurRound())));
            // 记录一下日志
//            CrossFeastLog.addLogFeastPvpBattle(new LogFeastPvpBattle(
//                    config.getActivityInfo().getActivityId(),
//                    attackedUserData.getCampId(),
//                    getCurRound(),
//                    attackedUserData.getUserId(),
//                    attackedUserData.getPvpProperty().getStateId(),
//                    attackedUserData.getPvpProperty().getAttrMap().getOrDefault(eFeastType.BattleAttrType.Atk.getValue(), 0L),
//                    attackedUserData.getPvpProperty().getAttrMap().getOrDefault(eFeastType.BattleAttrType.Hp.getValue(), 0L),
//                    attackUserData.getUserId(),
//                    attackUserData.getPvpProperty().getStateId(),
//                    battleRecord.getKillScore(),
//                    new Date(),
//                    Collections.emptyList(),
//                    battleRecord.getSeizeScore()
//            ));
        }
        // 通知被打的人
        builder.setAttackUserData(parseFeastPvpOtherUserTemp(attackUserData));
        builder.setAttack(parseFeastAttackedTemp(attackHelper));
        builder.setPvpUserData(parseFeastPvpUserDataTemp(attackedUserData));
        return builder;
    }

    private int getReviveCd(CrossFeastPvpUserData attackedUserData) {
        List<Integer> paramList = StringUtils.stringToIntegerList(config.getFEAST_PVP_RESURRECTION_CD(), "\\|");
        int initCd = paramList.get(0);
        int addCd = paramList.get(1);
        int maxCd = paramList.get(2);
        return Math.min(maxCd, initCd + attackedUserData.getReviveCnt() * addCd);
    }

    /**
     * 某轮战绩
     *
     */
    private ShanHeFeastProto.FeastPvpBattleScoreTemp.Builder parseFeastPvpBattleScoreTemp(CrossFeastPvpBattleRecord battleRecord) {
        // 统计战报
        ShanHeFeastProto.FeastPvpBattleScoreTemp.Builder builder = ShanHeFeastProto.FeastPvpBattleScoreTemp.newBuilder();
        int kill = 0;
        long killScore = 0;
        int seize = 0;
        long seizeScore = 0;
        if (battleRecord != null) {
            kill = battleRecord.getKill();
            killScore = battleRecord.getKillScore();
//            seize = battleRecord.getSeize();
            seizeScore = battleRecord.getSeizeScore();
        }
        builder.setKill(kill);
        builder.setKillScore(killScore);
//        builder.setSeize(seize);
        builder.setSeizeScore(seizeScore);
        return builder;
    }


    /**
     * 复活逻辑
     */
    public void revive(CrossFeastPvpUserData userData) {
        // 开始复活
        userData.setReviveCnt(userData.getReviveCnt() + 1);
        // 属性更新
        updatePvpProperty(userData);
    }

    /**
     * 更新pvp属性
     */
    public void updatePvpProperty(CrossFeastPvpUserData userData) {
        FeastPvpUserProperty pvpProperty = new FeastPvpUserProperty();
        // 获取pve属性
        FeastPveUserProperty pveProperty = userData.getPveProperty();
        // 设置下最新属性
        pvpProperty.setAttrMap(new HashMap<>(pveProperty.getAttrMap()));
        // 设置下当前血量
        pvpProperty.setHp(pveProperty.getAttrMap().getOrDefault(eFeastType.BattleAttrType.Hp.getValue(),0L));
        // 战力
        pvpProperty.setAbility(pveProperty.getPowerVal());
        pvpProperty.setStateId(pveProperty.getStateId());
        // 搞个特效
        int effectId = 1;
        FeastStateConfig FeastStateConfig = config.getStateConfigMap().get(pvpProperty.getStateId());
        if (FeastStateConfig != null) {
            if (FeastStateConfig.getMaxEffect() <= 3) {
                effectId = randomHelper.next(1, 3);
            } else {
                effectId = FeastStateConfig.getMaxEffect();
            }
        }
        pvpProperty.setEffectId(effectId);
        getProfileRadius(userData, true);
        userData.setPvpProperty(pvpProperty);
    }

    /**
     * * 用户等级榜单信息(当前轮次榜单)
     */
    public int getUserLevelRankListByCmd(long serverId, long userId) {
        CrossFeastPvpUserData userData = getPvpUserData(userId);
        if (userData == null) {
            return GameErrorCode.E_SHAN_HE_FEAST_PVP_USER_DATA_NOT_FOUND;
        }
        ShanHeFeastProto.FeastPvpGetLevelRankListRespMsg.Builder respMsg = ShanHeFeastProto.FeastPvpGetLevelRankListRespMsg.newBuilder();
        int rankNum = 0;
        int curRound = getCurRound();
        CrossFeastRankListModel listModel = roundRankListModel.get(curRound);
        if(listModel != null){
            for (CrossFeastRank rank : listModel.getRankList()) {
                rankNum++;
                long id = Long.valueOf(rank.getId());
                if (rankNum <= 3) {
                    // 前三才加入展示
                    respMsg.addRankList(parseFeastPvpRankSimpleTemp(id, rank.getValue(), rank.getParam(), rankNum));
                }
                if (id == userId) {
                    // 我的排名
                    respMsg.setMyRank(parseFeastPvpRankSimpleTemp(id, rank.getValue(), rank.getParam(), rankNum));
                }
                //提前结束
                if(rankNum >= 3 && respMsg.hasMyRank()){
                    break;
                }
            }
        }
        respMsg.setRet(0);
        // 获取当前的人数
        respMsg.setLeftNum(roomUserMap.size());
        // 回包
        sendPacket(serverId, Protocol.U_SHAN_HE_FEAST_PVP_GET_USER_LEVEL_RANK_LIST, respMsg, userId);
        return 0;
    }

    /**
     * 移动逻辑
     *
     * @param pvpUserData 用户数据
     * @param position    位置信息
     */
    private void move(CrossFeastPvpUserData pvpUserData, CrossFeastPvpPosition position) {
        pvpUserData.setPosition(position);
        pvpUserData.setLastPingPlaceTime(position.getTime());
    }

    /**
     * 初始化全部榜单
     */
    private void initAllRankList() {

        CrossFeastRankListModel userScoreRankModel = new CrossFeastRankListModel();
        CrossFeastRankListModel userPowerValRankModel = new CrossFeastRankListModel();
        CrossFeastRankListModel applyRankModel = new CrossFeastRankListModel();

        Map<Integer, CrossFeastRankListModel> battleRankModelMap = new ConcurrentHashMap<>();

        //轮次榜单
        int maxRound = 0;
        for (CrossFeastPvpUserData userData : pvpUserDataMap.values()) {
            if (!(userData.getPveProperty().getStateId() <= config.getInitStateId() && userData.getPveProperty().getPowerVal() <= 0L)) {

                //才力排行
                CrossFeastRank rank = new CrossFeastRank(String.valueOf(userData.getUserId()), userData.getPveProperty().getStateId(), userData.getUpdatePropertyTime(), String.valueOf(userData.getPveProperty().getPowerVal()));
                userPowerValRankModel.rankChange(rank);

                // 个人战绩排行
                long totalScore = calcTotalScore(userData);
                if (totalScore > 0) {
                    userScoreRankModel.rankChange(new CrossFeastRank(String.valueOf(userData.getUserId()), totalScore, userData.getUpdateScoreTime(), String.valueOf(userData.getTotalKillCnt())));
                }

                if(userData.isApply()){
                    applyRankModel.rankChange(new CrossFeastRank(String.valueOf(userData.getUserId()), userData.getPveProperty().getStateId(), userData.getUpdatePropertyTime(), String.valueOf(userData.getPveProperty().getPowerVal())));
                }

                for (Map.Entry<Integer, CrossFeastPvpBattleRecord> entry : userData.getRoundBattleRecordMap().entrySet()) {
                    int round = entry.getKey();
                    CrossFeastPvpBattleRecord value = entry.getValue();
                    if(round > maxRound){
                        maxRound = round;
                    }
                    if(!battleRankModelMap.containsKey(round)){
                        battleRankModelMap.put(round, new CrossFeastRankListModel());
                    }
                    CrossFeastRankListModel model = battleRankModelMap.get(round);
                    model.rankChange(new CrossFeastRank(String.valueOf(userData.getUserId()), value.getTotalScore(), userData.getUpdateScoreTime(), String.valueOf(value.getKill())));
                }
            }
        }

        userScoreRank = userScoreRankModel;
        userPowerRank = userPowerValRankModel;
        applyRankListModel = applyRankModel;
        roundRankListModel = battleRankModelMap;
    }

    public Set<Long> getUserIdListInActivityByCampId(int campId) {
        Set<Long> list = new HashSet<>();
        for (CrossFeastPvpUserData userData : pvpUserDataMap.values()) {
            if (!isAble(userData.getUserId())) {
                continue;
            }
            // 没资格不推
            if (!isAble(userData.getUserId())) {
                continue;
            }
            // 只同步本阵营的玩家
            if (userData.getCampId() != campId) {
                continue;
            }
            list.add(userData.getUserId());
        }
        return list;
    }

    /**
     * 用户报名
     *
     * @param userId
     * @param type
     * @param stateId
     * @param powerVal
     * @return
     */
    public int userApplyByCmd(long serverId, long userId, int type, int stateId, long powerVal) {
        CrossFeastPvpUserData userData = getPvpUserData(userId);
        if (userData == null) {
            return GameErrorCode.E_SHAN_HE_FEAST_PVP_USER_DATA_NOT_FOUND;
        }
        long nowTime = System.currentTimeMillis();
        ShanHeFeastProto.FeastPvpUserApplyRespMsg.Builder respMsg = ShanHeFeastProto.FeastPvpUserApplyRespMsg.newBuilder();
        if (type == 0) {
            // 如果报名了，需要更新榜单  ，仅在报名期更新
            if (userData.isApply()) {
                if (isApplyTime()) {
                    if (stateId != userData.getPveProperty().getStateId() || powerVal != userData.getPveProperty().getPowerVal()) {
                        userData.getPveProperty().setStateId(stateId);
                        userData.getPveProperty().setPowerVal(powerVal);
                        userData.setUpdatePropertyTime(nowTime);
                        // 更新榜单
                        applyRankListModel.rankChange(new CrossFeastRank(String.valueOf(userId), userData.getPveProperty().getStateId(), userData.getUpdatePropertyTime(), String.valueOf(userData.getPveProperty().getPowerVal())));
                    }
                }
                // 获取榜单信息
                int myRank = -1;
                long myValue = 0;
                String myParam = "";
                int rankNum = 0;
                String id = String.valueOf(userId);
                for (CrossFeastRank rank : applyRankListModel.getRankList()) {
                    rankNum++;
                    if (Objects.equals(rank.getId(), id)) {
                        myRank = rankNum;
                        myValue = rank.getValue();
                        myParam = rank.getParam();
                        break;
                    }
                }
                respMsg.setMyRank(parseFeastPvpRankTemp(userId, myValue, myParam, myRank));
            }
        } else if (type == 1) {
            // 报名
            if (userData.isApply()) {
                // 已报名，无需再报名
                return GameErrorCode.E_SHAN_HE_FEAST_PVP_IS_APPLY;
            }
            // 判断下是否在报名时间
            if (!isApplyTime()) {
                return GameErrorCode.E_SHAN_HE_FEAST_PVP_NOT_APPLY_TIME;
            }
            if (stateId <= 0 || powerVal <= 0) {
                return GameErrorCode.E_SHAN_HE_FEAST_PVP_NO_ABLE;
            }
            userData.getPveProperty().setStateId(stateId);
            userData.getPveProperty().setPowerVal(powerVal);
            userData.setUpdatePropertyTime(nowTime);
            // 标记报名状态
            userData.setApply(true);
            // 更新榜单
            applyRankListModel.rankChange(new CrossFeastRank(String.valueOf(userId), userData.getPveProperty().getStateId(), userData.getUpdatePropertyTime(), String.valueOf(userData.getPveProperty().getPowerVal())));

        }
        respMsg.setRet(0);
        respMsg.setApply(userData.isApply());
        respMsg.setAble(userData.isPvpAble());
        respMsg.setSettle(crossFeastPvpData.isSettle());
        // 回包
        MessageHelper.sendPacket(serverId, userId, YanQuMessageUtils.buildMessage(Protocol.U_SHAN_HE_FEAST_PVP_USER_APPLY, respMsg));
        return 0;
    }

    /**
     * 用户报名榜单信息
     */
    public int getUserApplyRankListByCmd(long serverId, long userId) {
        CrossFeastPvpUserData userData = getPvpUserData(userId);
        if (userData == null) {
            return GameErrorCode.E_SHAN_HE_FEAST_PVP_USER_DATA_NOT_FOUND;
        }
        ShanHeFeastProto.FeastGetUserApplyRankListRespMsg.Builder respMsg = ShanHeFeastProto.FeastGetUserApplyRankListRespMsg.newBuilder();
        int rankNum = 0;
        String id = String.valueOf(userId);
        for (CrossFeastRank rank : applyRankListModel.getRankList()) {
            rankNum++;
            respMsg.addRankList(parseFeastPvpRankTemp(Long.valueOf(rank.getId()), rank.getValue(), rank.getParam(), rankNum));
            if (Objects.equals(rank.getId(), id)) {
                // 我的排名
                respMsg.setMyRank(parseFeastPvpRankTemp(Long.valueOf(rank.getId()), rank.getValue(), rank.getParam(), rankNum));
            }
        }
        respMsg.setRet(0);
        // 回包
        sendPacket(serverId, Protocol.U_SHAN_HE_FEAST_PVP_GET_USER_APPLY_RANK_LIST, respMsg, userId);
        return 0;
    }

    private ShanHeFeastProto.FeastPvpRankTemp.Builder parseFeastPvpRankTemp(long userId, long value, String param, int rank) {
        ShanHeFeastProto.FeastPvpRankTemp.Builder temp = ShanHeFeastProto.FeastPvpRankTemp.newBuilder();
        temp.setUserId(userId);
        UserBaseInfo userBaseInfo = getUserBaseInfo(userId);
        if (userBaseInfo != null) {
            temp.setUserInfo(PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo));
        }
        temp.setValue(value);
        temp.setParam(param);
        temp.setRank(rank);
        return temp;
    }

    private ShanHeFeastProto.FeastPvpRankSimpleTemp.Builder parseFeastPvpRankSimpleTemp(long userId, long value, String param, int rank) {
        ShanHeFeastProto.FeastPvpRankSimpleTemp.Builder temp = ShanHeFeastProto.FeastPvpRankSimpleTemp.newBuilder();
        temp.setUserId(userId);
        UserBaseInfo userBaseInfo = getUserBaseInfo(userId);
        if (userBaseInfo != null) {
            temp.setName(userBaseInfo.getNickName());
        }
        temp.setValue(value);
        temp.setParam(param);
        temp.setRank(rank);
        return temp;
    }


    public UserBaseInfo getUserBaseInfo(long userId) {
        UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(userId);
        if (userBaseInfo != null) {
            return userBaseInfo;
        }
        CrossUserBaseInfo crossNpcUserBaseInfo = CrossNpcUserMgr.getCrossNpcUserBaseInfo(userId);
        if (crossNpcUserBaseInfo != null) {
            return crossNpcUserBaseInfo.getUserBaseInfo();
        }
        return null;
    }

    public ShanHeFeastProto.FeastPvpUserDataTemp.Builder parseFeastPvpUserDataTemp(CrossFeastPvpUserData pvpUserData) {
        if (pvpUserData == null) {
            return null;
        }
        ShanHeFeastProto.FeastPvpUserDataTemp.Builder builder = ShanHeFeastProto.FeastPvpUserDataTemp.newBuilder();
        builder.setActivityId(config.getActivityInfo().getActivityId());
        builder.setProperty(parseFeastUserPvpPropertyTemp(pvpUserData));
        builder.setTransferTime(pvpUserData.getTransferTime());
        builder.setPlaceId(pvpUserData.getPlaceId());
        builder.setTransferTime(pvpUserData.getTransferTime());
        builder.setAttackTime(pvpUserData.getAttackTime());
        builder.setAttackedTime(pvpUserData.getAttackedTime());
        builder.setReviveTime(pvpUserData.getReviveTime());
        builder.setUpDemandTime(pvpUserData.getUpDemandTime());
        builder.setDownDemandTime(pvpUserData.getDownDemandTime());
        builder.setKillCnt(pvpUserData.getKillCnt());
        builder.setReviveCnt(pvpUserData.getReviveCnt());
        builder.setLifeKill(pvpUserData.getBattleRecord().getKill());
        return builder;
    }

    public ShanHeFeastProto.FeastPvpUserPropertyTemp.Builder parseFeastUserPvpPropertyTemp(CrossFeastPvpUserData userData) {
        if (userData == null) {
            return null;
        }
        Map<Integer, Long> attrMap = userData.getPvpProperty().getAttrMap();
        ShanHeFeastProto.FeastPvpUserPropertyTemp.Builder builder = ShanHeFeastProto.FeastPvpUserPropertyTemp.newBuilder();
        builder.setAttack(attrMap.getOrDefault(eFeastType.BattleAttrType.Atk.getValue(), 0L));
        builder.setTotalHp(attrMap.getOrDefault(eFeastType.BattleAttrType.Hp.getValue(), 0L));
        builder.setAttackSpeed(Math.toIntExact(attrMap.getOrDefault(eFeastType.BattleAttrType.AtkSpeed.getValue(), 0L)));
        builder.setHp(userData.getPvpProperty().getHp());
        builder.setAbility(userData.getPvpProperty().getAbility());
        builder.setStateId(userData.getPvpProperty().getStateId());
        builder.setEffectId(userData.getPvpProperty().getEffectId());
        return builder;
    }

    public ShanHeFeastProto.FeastPvpUserPropertyTemp.Builder parseFeastUserPvePropertyTemp(CrossFeastPvpUserData userData) {
        if (userData == null) {
            return null;
        }
        ShanHeFeastProto.FeastPvpUserPropertyTemp.Builder builder = ShanHeFeastProto.FeastPvpUserPropertyTemp.newBuilder();
        Map<Integer, Long> attrMap = userData.getPveProperty().getAttrMap();
        builder.setAttack(attrMap.getOrDefault(eFeastType.BattleAttrType.Atk.getValue(), 0L));
        builder.setTotalHp(attrMap.getOrDefault(eFeastType.BattleAttrType.Hp.getValue(), 0L));
        builder.setHp(attrMap.getOrDefault(eFeastType.BattleAttrType.Hp.getValue(), 0L));
        builder.setAttackSpeed(Math.toIntExact(attrMap.getOrDefault(eFeastType.BattleAttrType.Atk.getValue(), 0L)));
        builder.setAbility(userData.getPveProperty().getPowerVal());
        builder.setStateId(userData.getPveProperty().getStateId());
        builder.setEffectId(userData.getPvpProperty().getEffectId());
        return builder;
    }

    public FeastPveUserProperty parseFeastUserPveProperty(ShanHeFeastProto.FeastPvePropertyForCrossTemp temp) {
        FeastPveUserProperty property = new FeastPveUserProperty();
        property.setPowerVal(temp.getPowerVal());
        property.setStateId(temp.getStateId());
        property.setPracticeSpeed(temp.getPracticeSpeed());
        property.setImageId(temp.getImageId());
        // 属性
        for (ShanHeFeastProto.FeastAttrInfoTemp attrTemp : temp.getAttrListList()) {
            int attrId = attrTemp.getAttrId();
            long value = attrTemp.getAttrValue();
            property.getAttrMap().put(attrId, value);
        }
        return property;
    }

    public ShanHeFeastProto.FeastPvpPositionTemp.Builder parseFeastPvpPositionTemp(CrossFeastPvpPosition position) {
        if (position == null) {
            return null;
        }
        ShanHeFeastProto.FeastPvpPositionTemp.Builder builder = ShanHeFeastProto.FeastPvpPositionTemp.newBuilder();
        builder.setX((int) Math.floor(position.getX() * 10000));
        builder.setY((int) Math.floor(position.getY() * 10000));
        builder.setDirX((int) Math.floor(position.getDirX() * 10000));
        builder.setDirY((int) Math.floor(position.getDirY() * 10000));
        builder.setTime(position.getTime());
        return builder;
    }

    public ShanHeFeastProto.FeastPvpPlaceInfoTemp.Builder parseFeastPvpPlaceInfoTemp(CrossFeastPvpPlaceData placeData, long playerId) {
        if (placeData == null) {
            return null;
        }
        ShanHeFeastProto.FeastPvpPlaceInfoTemp.Builder builder = ShanHeFeastProto.FeastPvpPlaceInfoTemp.newBuilder();
        builder.setPlaceId(placeData.getPlaceId());
        // 组装房间玩家信息
        for (Long userId : getRoomUserList(placeData.getPlaceId())) {
            CrossFeastPvpUserData pvpUserData = getPvpUserData(userId);
            if (pvpUserData == null) {
                continue;
            }
            if (pvpUserData.getUserState() == 1 && pvpUserData.getUserId() != playerId) {
                continue;
            }
            builder.addUser(parseFeastPvpOtherUserTemp(pvpUserData));
        }
        return builder;
    }

    public ShanHeFeastProto.FeastPvpPlayerSimpleTempMsg.Builder parseFeastPvpPlayerSimpleTempMsg(CrossFeastPvpUserData userData) {
        long userId = userData.getUserId();
        ShanHeFeastProto.FeastPvpPlayerSimpleTempMsg.Builder builder = ShanHeFeastProto.FeastPvpPlayerSimpleTempMsg.newBuilder();
        if (isNpc(userId)) {
            CrossFeastNpcDataHelper dataHelper = npcDataMap.get(userId);
            builder.setDecoration(dataHelper.getDecoration());
            builder.setNickName(dataHelper.getNickName());
            builder.setUserId(userId);
            builder.setServerId(dataHelper.getServerId());
        } if(isRobot(userId)){
            CrossFeastNpcDataHelper dataHelper = robotDataMap.get(userId);
            builder.setDecoration(dataHelper.getDecoration());
            builder.setNickName(dataHelper.getNickName());
            builder.setUserId(userId);
            builder.setServerId(dataHelper.getServerId());
        } else {
            UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(userId);
            if (userBaseInfo != null) {
                builder.setDecoration(userBaseInfo.getDecoration());
                builder.setNickName(userBaseInfo.getNickName());
                builder.setServerId(userBaseInfo.getServerId());
                builder.setUserId(userId);
            }
        }
        return builder;
    }

    public ShanHeFeastProto.FeastPvpOtherUserTemp.Builder parseFeastPvpOtherUserTemp(CrossFeastPvpUserData pvpUserData) {
        if (pvpUserData == null) {
            return null;
        }
        ShanHeFeastProto.FeastPvpOtherUserTemp.Builder builder = ShanHeFeastProto.FeastPvpOtherUserTemp.newBuilder();
        builder.setPlayerData(parseFeastPvpPlayerSimpleTempMsg(pvpUserData));
        builder.setProperty(parseFeastUserPvpPropertyTemp(pvpUserData));
        builder.setPlaceId(pvpUserData.getPlaceId());
        builder.setPosition(parseFeastPvpPositionTemp(pvpUserData.getPosition()));
        builder.setReviveTime(pvpUserData.getReviveTime());
        builder.setUpDemandTime(pvpUserData.getUpDemandTime());
        builder.setDownDemandTime(pvpUserData.getDownDemandTime());
        builder.setSpeedUpEndTime(pvpUserData.getSpeedEndTime());
        builder.setProtectTime(pvpUserData.getProtectTime());
        return builder;
    }

    public CrossFeastPvpPosition parseCrossFeastPvpPosition(ShanHeFeastProto.FeastPvpPositionTemp temp) {
        CrossFeastPvpPosition position = new CrossFeastPvpPosition();
        position.setX(temp.getX());
        position.setY(temp.getY());
        position.setDirX(temp.getDirX());
        position.setDirY(temp.getDirY());
        position.setTime(temp.getTime());
        return position;
    }

    public ShanHeFeastProto.FeastPvpUserDetailTemp.Builder parseFeastPvpUserDetailTemp(CrossFeastPvpUserData pvpUserData) {
        if (pvpUserData == null) {
            return null;
        }
        ShanHeFeastProto.FeastPvpUserDetailTemp.Builder builder = ShanHeFeastProto.FeastPvpUserDetailTemp.newBuilder();
        UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(pvpUserData.getUserId());
        if (userBaseInfo == null) {
            return null;
        }
        builder.setUserId(pvpUserData.getUserId());
        builder.setUser(PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo));
        builder.setProperty(parseFeastUserPvpPropertyTemp(pvpUserData));
        return builder;
    }

    public ShanHeFeastProto.FeastPvpUserDetailTemp.Builder parseFeastPveUserDetailTemp(CrossFeastPvpUserData userData) {
        if (userData == null) {
            return null;
        }
        ShanHeFeastProto.FeastPvpUserDetailTemp.Builder builder = ShanHeFeastProto.FeastPvpUserDetailTemp.newBuilder();
        UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(userData.getUserId());
        if (userBaseInfo == null) {
            return null;
        }
        builder.setUserId(userData.getUserId());
        builder.setUser(PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo));
        builder.setProperty(parseFeastUserPvePropertyTemp(userData));
        return builder;
    }

    public CrossFeastPvpData getCrossFeastPvpData() {
        return crossFeastPvpData;
    }

    public boolean isCampNotice(CrossFeastPvpNoticeData noticeData) {
        return false;
    }

    /**
     * 增加公告
     *
     * @param noticeData 公告信息
     * @param userId1 操作者id
     * @param userId2 被操作者id
     */
    public void addPvpNoticeData(CrossFeastPvpNoticeData noticeData, long userId1, long userId2) {
        // 添加操作者信息
        if (userId1 != 0) {
            CrossFeastPvpUserData userData = getPvpUserData(userId1);
            if (userData != null) {
                CrossFeastPvpNoticeUserData noticeUserData = new CrossFeastPvpNoticeUserData();
                noticeUserData.setUserId(userData.getUserId());
                if (isNpc(userId1)) {
                    CrossFeastNpcDataHelper dataHelper = npcDataMap.get(userId1);
                    if (dataHelper != null) {
                        noticeUserData.setNickName(dataHelper.getNickName());
                        noticeUserData.setServerId(dataHelper.getServerId());
                        noticeUserData.setDecoration(dataHelper.getDecoration());
                    }
                } if(isRobot(userId1)){
                    CrossFeastNpcDataHelper dataHelper = robotDataMap.get(userId1);
                    if (dataHelper != null) {
                        noticeUserData.setNickName(dataHelper.getNickName());
                        noticeUserData.setServerId(dataHelper.getServerId());
                        noticeUserData.setDecoration(dataHelper.getDecoration());
                    }
                }else {
                    CrossUserBaseInfo userBaseInfo = CrossUserMgr.getCrossUserBaseInfo(userId1);
                    if (userBaseInfo != null && userBaseInfo.getUserBaseInfo() != null) {
                        noticeUserData.setNickName(userBaseInfo.getUserBaseInfo().getNickName());
                        noticeUserData.setServerId(userBaseInfo.getUserBaseInfo().getServerId());
                        noticeUserData.setDecoration(userBaseInfo.getUserBaseInfo().getDecoration());
                    }
                }
                noticeUserData.setStateId(userData.getPveProperty().getStateId());
                noticeData.setUser1(noticeUserData);
            }
        }
        // 添加被操作者信息
        if (userId2 != 0) {
            CrossFeastPvpUserData userData = getPvpUserData(userId2);
            if (userData != null) {
                CrossFeastPvpNoticeUserData noticeUserData = new CrossFeastPvpNoticeUserData();
                noticeUserData.setUserId(userData.getUserId());
                if (isNpc(userId2)) {
                    CrossFeastNpcDataHelper dataHelper = npcDataMap.get(userId2);
                    if (dataHelper != null) {
                        noticeUserData.setNickName(dataHelper.getNickName());
                        noticeUserData.setServerId(dataHelper.getServerId());
                        noticeUserData.setDecoration(dataHelper.getDecoration());
                    }
                } if(isRobot(userId2)){
                    CrossFeastNpcDataHelper dataHelper = robotDataMap.get(userId2);
                    if (dataHelper != null) {
                        noticeUserData.setNickName(dataHelper.getNickName());
                        noticeUserData.setServerId(dataHelper.getServerId());
                        noticeUserData.setDecoration(dataHelper.getDecoration());
                    }
                }else {
                    CrossUserBaseInfo userBaseInfo = CrossUserMgr.getCrossUserBaseInfo(userId2);
                    if (userBaseInfo != null && userBaseInfo.getUserBaseInfo() != null) {
                        noticeUserData.setNickName(userBaseInfo.getUserBaseInfo().getNickName());
                        noticeUserData.setServerId(userBaseInfo.getUserBaseInfo().getServerId());
                        noticeUserData.setDecoration(userBaseInfo.getUserBaseInfo().getDecoration());
                    }
                }
                noticeUserData.setStateId(userData.getPveProperty().getStateId());
                noticeData.setUser2(noticeUserData);
            }
        }
        noticeData.setInsertOption();
        ShanHeFeastProto.FeastNoticeSyncMsg.Builder syncMsg = ShanHeFeastProto.FeastNoticeSyncMsg.newBuilder();
        if (isCampNotice(noticeData)) {

        } else {
            // 全服公告
            synchronized (noticeDataList) {
                while (noticeDataList.size() > config.getFEAST_PVP_NOTICE_NUM()) {
                    noticeDataList.removeFirst();
                }
                noticeDataList.add(noticeData);
            }
            ShanHeFeastProto.FeastNoticeTemp.Builder noticeTemp = parseFeastNoticeTemp(noticeData);
            if (noticeTemp != null) {
                syncMsg.setNotice(noticeTemp);
                // 推送公告给在线用户
                sendPacketToAll(Protocol.U_SHAN_HE_FEAST_NOTICE_SYNC, syncMsg, new ArrayList<>(inPvpActivity));
            }
        }
    }

    public void sendChatByCmd(long userId, CrossActivityProto.CrossActivityChatReqMsg.Builder reqMsg) {
        int range = 0;
        int id = 0;
        if (eMessageType.FeastPublicChat.getValue() == reqMsg.getMsg().getType()) {
            range = CrossFeastChatLogic.RANGE_ALL;
            id = config.getActivityInfo().getActivityId();
            // 公屏聊天加上阵营
            WorldMessageProto.WorldMessageTempMsg.Builder message = reqMsg.getMsg().toBuilder();
//            message.setExtraParams(String.valueOf(getCampByUserId(userId)));
            reqMsg.setMsg(message);
        } else if (eMessageType.FeastCampChat.getValue() == reqMsg.getMsg().getType()) {
            range = CrossFeastChatLogic.RANGE_CAMP;
//            id = getCampByUserId(userId);
        }

        if (range <= 0 || id <= 0) {
            return;
        }

        chatLogic.chat(range, id, 1, reqMsg.getMsg());
    }

    public void getChatByCmd(long userId, List<Integer> paramList) {
        if (paramList.isEmpty()) {
            return;
        }
        List<WorldMessageProto.WorldMessageTempMsg> dataList = new ArrayList<>();
        for (int range : paramList) {
            int id = 0;
            if (range == CrossFeastChatLogic.RANGE_ALL) {
                id = config.getActivityInfo().getActivityId();
            } else if (range == CrossFeastChatLogic.RANGE_CAMP) {
//                id = getCampByUserId(userId);
            }

            if (range <= 0 || id <= 0) {
                continue;
            }
            dataList.addAll(chatLogic.getChatMsg(range, id));
        }
        CrossActivityProto.CrossActivityChatListRespMsg.Builder respMsg = CrossActivityProto.CrossActivityChatListRespMsg.newBuilder();
        respMsg.setActivityId(config.getActivityInfo().getActivityId());

        if (dataList.size() > 0) {
            dataList.sort(Comparator.comparingLong(WorldMessageProto.WorldMessageTempMsg::getSendTime));
            WorldMessageProto.WorldMessageListMsg.Builder worldMessageListMsg = WorldMessageProto.WorldMessageListMsg.newBuilder();
            worldMessageListMsg.addAllDataList(dataList);
            respMsg.setDataList(worldMessageListMsg);
        }
        UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(userId);
        if (userBaseInfo != null) {
            YanQuMessage pbMsg = YanQuMessageUtils.buildMessage(Protocol.U_CROSS_ACTIVITY_CHAT_LIST, respMsg);
            MessageHelper.sendPacket(userBaseInfo.getServerId(), userId, pbMsg);
        }
    }

    public void syncChat(int range, int id, WorldMessageProto.WorldMessageTempMsg chatMsg) {
        List<Long> userIdList = new ArrayList<>();
        if (range == CrossFeastChatLogic.RANGE_ALL) {
            // 所有人都要接收，所以换个发包方式
            YanQuMessage pbMsg = YanQuMessageUtils.buildMessage(Protocol.A_WORLD_MESSAGE_TRANSFER, chatMsg);
            for (long serverId : config.getActivityInfo().getServerIdList()) {
                MessageHelper.sendPacket(serverId, 0, pbMsg);
            }
            return;
        } else if (range == CrossFeastChatLogic.RANGE_CAMP) {
            userIdList = pvpUserDataMap.values().stream().filter(item -> item.getCampId() == id).mapToLong(CrossFeastPvpUserData::getUserId).boxed().collect(Collectors.toList());
        }
        if (!userIdList.isEmpty()) {
            sendPacketToAll(ClientProtocol.U_WORLD_MESSAGE_SYNC, chatMsg.toBuilder(), userIdList);
        }
    }

    public void getRankRewardByCmd(long serverId, long userId, ShanHeFeastProto.FeastGetRankRewardReqMsg reqMsg) {
        int ret = getRankReward(userId, reqMsg.getConditionType());
        if (ret != 0) {
            ShanHeFeastProto.FeastGetRankRewardRespMsg.Builder builder = ShanHeFeastProto.FeastGetRankRewardRespMsg.newBuilder();
            builder.setRet(ret);
            sendPacket(serverId, ClientProtocol.U_SHAN_HE_FEAST_GET_RANK_REWARD, builder, userId);
        }
    }

    public void getUserRankListByCmd(long serverId, long userId, ShanHeFeastProto.FeastGetUserRankReqMsg reqMsg) {
        int type = reqMsg.getType();

        long myValue = calcTotalScore(getPvpUserData(userId));
        String myId = String.valueOf(userId);
        LinkedList<CrossFeastRank> rankList;
        int maxRank = 100;

        if (type == 1) {
            // 【个人榜】
            rankList = userScoreRank.getRankList();
            maxRank = userMaxRankConfig;
        } else {
            return; // 参数错误
        }

        ShanHeFeastProto.FeastGetUserRankRespMsg.Builder builder = ShanHeFeastProto.FeastGetUserRankRespMsg.newBuilder();
        builder.setRet(0);

        int myRank = -1;
        int rankNum = 0;
        for (CrossFeastRank rank : rankList) {
            rankNum++;
            if (rankNum > maxRank) {
                break;
            }
            if (Objects.equals(rank.getId(), myId)) {
                myRank = rankNum;
            }
            builder.addRank(parseFeastUserRankMsg(rank));
        }

        builder.setMyRank(myRank);
        builder.setMyValue(myValue);
        sendPacket(serverId, ClientProtocol.U_SHAN_HE_FEAST_GET_USER_RANK_LIST, builder, userId);
    }

    public ShanHeFeastProto.FeastUserRankMsg.Builder parseFeastUserRankMsg(CrossFeastRank rank) {
        long userId = Long.parseLong(rank.getId());
        UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(userId);
        if (userBaseInfo == null) {
            userBaseInfo = new UserBaseInfo();
        }

        ShanHeFeastProto.FeastUserRankMsg.Builder builder = ShanHeFeastProto.FeastUserRankMsg.newBuilder();
        builder.setUserId(userId);
        builder.setPlayerBaseData(PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo));
        builder.setValue(rank.getValue());
        return builder;
    }

    /**
     * 领取榜单奖励
     */
    private int getRankReward(long userId, int conditionType) {
        CrossFeastPvpUserData userData = getPvpUserData(userId);
        if (userData == null) {
            return GameErrorCode.E_SHAN_HE_FEAST_PVP_USER_NOT_FOUND;
        }
        // 拿榜单
        String myId;
        LinkedList<CrossFeastRank> rankList;
        if (conditionType == eGamePlayerEventType.FeastPersonalScoreRank.getValue()) {
            rankList = userScoreRank.getRankList();
            myId = String.valueOf(userId);
        } else {
            return GameErrorCode.E_SHAN_HE_FEAST_PARAM_ERROR;
        }
        // 拿榜单排名
        int myRank = -1;
        int num = 0;
        for (CrossFeastRank rank : rankList) {
            num++;
            if (Objects.equals(rank.getId(), myId)) {
                myRank = num;
                break;
            }
        }
        ShanHeFeastProto.CrossFeastGetRankRewardRespMsg.Builder builder = ShanHeFeastProto.CrossFeastGetRankRewardRespMsg.newBuilder();
        builder.setRet(0);
        builder.setActivityId(config.getActivityInfo().getActivityId());
        builder.setConditionType(conditionType);
        builder.setRank(myRank);
        sendPacket(GameProtocol.S_SHAN_HE_FEAST_GET_RANK_REWARD_FROM_CROSS, builder, userId);
        return 0;
    }

    /**
     * 添加被打同步消息
     */
    public void addPvpAttackSyncData(int placeId, CrossFeastPvpAttackHelper attack) {
        synchronized (attackSyncListMap) {
            List<CrossFeastPvpAttackHelper> attackSyncList = attackSyncListMap.getOrDefault(placeId, new ArrayList<>());
            attackSyncList.add(attack);
            attackSyncListMap.put(placeId, attackSyncList);
        }
    }

    /**
     * 添加升级降级同步消息
     */
    public void addPvpDemandSyncData(int placeId, ShanHeFeastProto.FeastUpDownDemandTemp temp) {
        synchronized (demandSyncListMap) {
            List<ShanHeFeastProto.FeastUpDownDemandTemp> syncList = demandSyncListMap.getOrDefault(placeId, new ArrayList<>());
            syncList.add(temp);
            demandSyncListMap.put(placeId, syncList);
        }
    }

    /**
     * 添加房间操作同步消息
     */
    public void addPvpOptSyncData(int placeId, ShanHeFeastProto.FeastPlaceOptTemp temp) {
        synchronized (optSyncListMap) {
            List<ShanHeFeastProto.FeastPlaceOptTemp> syncList = optSyncListMap.getOrDefault(placeId, new ArrayList<>());
            syncList.add(temp);
            optSyncListMap.put(placeId, syncList);
        }
    }


    /**
     * 通知游戏服condition更新值
     */
    private void notifyConditionChange(long userId, eGamePlayerEventType type, long value, int round) {
        ShanHeFeastProto.CrossFeastNotifyConditionRespMsg.Builder builder = ShanHeFeastProto.CrossFeastNotifyConditionRespMsg.newBuilder();
        builder.setUserId(userId);
        builder.setConditionType(type.getValue());
        builder.setValue(value);
        builder.setRound(round);
        sendPacket(GameProtocol.S_SHAN_HE_FEAST_NOTIFY_CONDITION_FROM_CROSS, builder, userId);
    }

    public CrossFeastRankListModel getUserScoreRank() {
        return userScoreRank;
    }

    private Map<Long, CrossFeastPvpUserData> robotUserMap = new ConcurrentHashMap<>();

    private Map<Long, CrossFeastNpcDataHelper> robotDataMap = new ConcurrentHashMap<>();

    private long robotId = 1000000;

    private Map<Long, CrossFeastPvpUserData> npcUserMap = new ConcurrentHashMap<>();

    private Map<Long, CrossFeastNpcDataHelper> npcDataMap = new ConcurrentHashMap<>();

    private long npcId = 1;

    private CrossFeastPvpUserData genNpcUserData(long npcId, String param, int placeId) {
        if (!npcUserMap.containsKey(npcId)) {
            CrossFeastPvpUserData npc = new CrossFeastPvpUserData();
            npc.setActivityId(config.getActivityInfo().getActivityId());
            npc.setUserId(npcId);
            // 出生地id
            npc.setPlaceId(placeId);
            // 可传送时间
            npc.setTransferTime(System.currentTimeMillis());
            // 可复活时间
            npc.setReviveTime(System.currentTimeMillis());
            // 生命标识
            npc.setReviveCnt(0);
            npc.setPvpAble(true);
            npc.setApply(true);
            // 造一份假属性
            FeastPveUserProperty pveProperty = npc.getPveProperty();
            List<Long> paramList = StringUtils.stringToLongList(param, "\\|");
            Map<Integer, Long> attrMap = new HashMap<>();
            attrMap.put(eFeastType.BattleAttrType.Hp.getValue(), paramList.get(0));
            attrMap.put(eFeastType.BattleAttrType.Atk.getValue(), paramList.get(1));
            attrMap.put(eFeastType.BattleAttrType.CritRatio.getValue(), paramList.get(2));
            attrMap.put(eFeastType.BattleAttrType.TenacityRatio.getValue(), paramList.get(3));
            attrMap.put(eFeastType.BattleAttrType.AtkSpeed.getValue(), paramList.get(4));
            attrMap.put(eFeastType.BattleAttrType.DodgeRatio.getValue(), paramList.get(5));
            attrMap.put(eFeastType.BattleAttrType.HitRatio.getValue(), paramList.get(6));
            attrMap.put(eFeastType.BattleAttrType.SuckRatio.getValue(), paramList.get(7));
            pveProperty.setAttrMap(attrMap);
            pveProperty.setPowerVal(paramList.get(8));
            pveProperty.setStateId(paramList.get(9).intValue());
            npc.setPveProperty(pveProperty);
            updatePvpProperty(npc);
            npcUserMap.put(npcId, npc);
            // 顺便生成一下信息
            CrossFeastNpcDataHelper dataHelper = new CrossFeastNpcDataHelper();
            dataHelper.setUserId(npcId);
            List<Long> list = new ArrayList<>(config.getActivityInfo().getServerIdList());
            dataHelper.setServerId(list.get(randomHelper.next(0, list.size())));
            dataHelper.setNickName("npc" + npcId);
            dataHelper.setDecoration(String.valueOf(randomGetNpcHeadId()));
            npcDataMap.put(npcId, dataHelper);
        }
        return npcUserMap.get(npcId);
    }

    private int randomGetNpcHeadId() {
        List<Integer> list = new ArrayList<>();
        for (int i = 106055; i <= 106074; i++) {
            list.add(i);
        }
        return list.get(randomHelper.next(0, list.size()));
    }


    // =======================命令测试====================
    public void testCode(long userId, String code) {
        CrossFeastPvpUserData userData = getPvpUserData(userId);
        if (userData == null) {
            return;
        }
        if("/shhbm".equals(code)){
            for (Map.Entry<Long, CrossFeastPvpUserData> entry : pvpUserDataMap.entrySet()) {
                CrossFeastPvpUserData value = entry.getValue();
                if (!value.isApply()) {
                    if (isApplyTime() && value.getPveProperty().getPowerVal() > 0) {
                        value.setApply(true);
                        // 更新榜单
                        applyRankListModel.rankChange(new CrossFeastRank(String.valueOf(value.getUserId()), value.getPveProperty().getStateId(),
                                value.getUpdatePropertyTime(), String.valueOf(value.getPveProperty().getPowerVal())));
                    }
                }
            }
        }
        if("/shhjoin".equals(code)){
            joinPlace(1, getPvpUserData(userId));
        }
        // 踢出所有npc
        if (code.startsWith("/shhResetAllNpc")) {
            npcDataMap.clear();
            npcUserMap.clear();
            npcId = 1;
            return;
        }
        if (code.startsWith("/shhHp")) {
            String param = code.substring("/shhHp".length() + 1);
            if (!StringUtils.isNullOrEmpty(param)) {
                FeastPvpUserProperty pvpProperty = userData.getPvpProperty();
                pvpProperty.setHp(Long.parseLong(param));
                pvpProperty.getAttrMap().put(eFeastType.BattleAttrType.Hp.getValue(), Long.parseLong(param));
            }
        }
        if (code.startsWith("/shhpvp")) {
            userData.setPvpAble(true);
            String param = code.substring("shhpvp".length() + 1);
            if (!StringUtils.isNullOrEmpty(param)) {
                FeastPveUserProperty pveProperty = userData.getPveProperty();
                List<Long> paramList = StringUtils.stringToLongList(param, "\\|");
                Map<Integer, Long> attrMap = new HashMap<>();
                attrMap.put(eFeastType.BattleAttrType.Hp.getValue(), paramList.get(0));
                attrMap.put(eFeastType.BattleAttrType.Atk.getValue(), paramList.get(1));
                attrMap.put(eFeastType.BattleAttrType.CritRatio.getValue(), paramList.get(2));
                attrMap.put(eFeastType.BattleAttrType.TenacityRatio.getValue(), paramList.get(3));
                attrMap.put(eFeastType.BattleAttrType.AtkSpeed.getValue(), paramList.get(4));
                attrMap.put(eFeastType.BattleAttrType.DodgeRatio.getValue(), paramList.get(5));
                attrMap.put(eFeastType.BattleAttrType.HitRatio.getValue(), paramList.get(6));
                attrMap.put(eFeastType.BattleAttrType.SuckRatio.getValue(), paramList.get(7));
                pveProperty.setAttrMap(attrMap);
                pveProperty.setPowerVal(paramList.get(8));
                pveProperty.setStateId(paramList.get(9).intValue());
                userData.setPveProperty(pveProperty);
                updatePvpProperty(userData);
            }
        }
        if (code.startsWith("effect")) {
            int param = Integer.parseInt(code.substring("effect".length() + 1));
            userData.getPvpProperty().setEffectId(param);
        }
        if (code.startsWith("/shhrandomNpc")) {
            String param = code.substring("/shhrandomNpc".length());
            int count = Integer.parseInt(param);
            for (int i = 0; i < count; i++) {
                int placeId = 1;
                StringBuilder sb = new StringBuilder();
                List<FeastStateConfig> stateConfigs = new ArrayList<>(config.getStateConfigMap().values());
                sb.append(randomHelper.next(1, 5000)).append("|")
                        .append(randomHelper.next(1, 6000)).append("|")
                        .append(randomHelper.next(1, 1000)).append("|")
                        .append(randomHelper.next(1, 1000)).append("|")
                        .append(randomHelper.next(1000, 5000)).append("|")
                        .append(randomHelper.next(1, 1000)).append("|")
                        .append(randomHelper.next(1, 1000)).append("|")
                        .append(randomHelper.next(1, 1000)).append("|")
                        .append(randomHelper.next(1, 1000)).append("|")
                        .append(stateConfigs.get(randomHelper.next(0, stateConfigs.size() - 1)).getId()).append("|");
                CrossFeastPvpUserData pvpUserData = genNpcUserData(npcId++, sb.toString(), placeId);
                // 加入房间
                joinPlace(placeId, pvpUserData);
            }
        }
        if (code.equals("clearNotice")) {
            noticeDataList.clear();
        }
        if (code.startsWith("notice")) {
            String param = code.substring("notice".length() + 1);
            String[] split = param.split("@");
            int type = Integer.parseInt(split[0]);
            CrossFeastPvpNoticeData noticeData = new CrossFeastPvpNoticeData();
            noticeData.setActivityId(config.getActivityInfo().getActivityId());
            noticeData.setRound(getCurRound());
            noticeData.setNoticeType(type);
            noticeData.setContent(split[1]);
            noticeData.setNoticeTime(System.currentTimeMillis());
            noticeData.setIsRoll(Integer.parseInt(split[2]));
            addPvpNoticeData(noticeData, userId, userId);
        }
        if (code.startsWith("gz")) {
            String param = code.substring("gz".length() + 1);
            userData.getPvpProperty().setHp(0);
            userData.setReviveTime(System.currentTimeMillis() + DateHelper.SECOND_MILLIONS * Long.parseLong(param));
            ShanHeFeastProto.FeastAttackedUserSyncMsg.Builder builder = ShanHeFeastProto.FeastAttackedUserSyncMsg.newBuilder();
            // 通知被打的人
            builder.setAttackUserData(parseFeastPvpOtherUserTemp(userData));
            builder.setAttack(parseFeastAttackedTemp(new CrossFeastPvpAttackHelper()));
            builder.setPvpUserData(parseFeastPvpUserDataTemp(userData));
            sendPacket(ClientProtocol.U_SHAN_HE_FEAST_ATTACKED_USER_SYNC, builder, userId);
        }
    }

    /***
     * 新增
     */
    public void playerMoveHandler(CrossFeastPvpUserData userData, CrossFeastPvpPosition position, boolean needSync) {
        if (position.getTime() < userData.getPosition().getTime()) {
            // 位置早于当前，丢掉
            return;
        }
        if(userData.getPlaceId() == 0){
            return;
        }
        FeastPvpPlaceConfig placeConfig = config.getPlaceConfigMap().get(userData.getPlaceId());
        if(placeConfig == null){
            return;
        }
        // 更新下位置
        userData.getPosition().setX(calcX(position.getX(), placeConfig));
        userData.getPosition().setY(calcY(position.getY(), placeConfig));
        userData.getPosition().setDirX(position.getDirX());
        userData.getPosition().setDirY(position.getDirY());
        userData.getPosition().setTime(position.getTime());
        userData.setLastPingPlaceTime(position.getTime());
        // 广播
        if (needSync) {
            addPlayerPosition(userData.getPlaceId(), userData.getUserId(), userData.getPosition());
        }
    }

    public void pvpNpcMoveTask() {
        if (!isBattleTime() || crossFeastPvpData.isSettle()) {
            return;
        }
        for (Long userId : npcUserMap.keySet()) {
            CrossFeastPvpUserData userData = getPvpUserData(userId);
            if (userData == null || !userData.isLive()) {
                continue;
            }
            // 位置移动
            npcMoveHandler(userData);
        }

        for (Long userId : robotUserMap.keySet()) {
            CrossFeastPvpUserData userData = getPvpUserData(userId);
            if (userData == null || !userData.isLive()) {
                continue;
            }
            // 位置移动
            npcMoveHandler(userData);
        }
    }

    public void pvpNpcActionTask() {
        if (!isBattleTime() || crossFeastPvpData.isSettle()) {
            return;
        }
        long nowTime = System.currentTimeMillis();

        for (Long userId : npcUserMap.keySet()) {
            CrossFeastPvpUserData userData = getPvpUserData(userId);
            if (userData == null || !userData.isLive()) {
                continue;
            }
            // 更新下npc的方向
            Coordinate direction = randomDir();
            userData.getPosition().setDirX(direction.getX());
            userData.getPosition().setDirY(direction.getY());
            userData.getPosition().setTime(nowTime);
            // 广播下
            addPlayerPosition(userData.getPlaceId(), userData.getUserId(), userData.getPosition());
        }

        for (Long userId : robotUserMap.keySet()) {
            CrossFeastPvpUserData userData = getPvpUserData(userId);
            if (userData == null || !userData.isLive()) {
                continue;
            }
            // 更新下npc的方向
            Coordinate direction = randomDir();
            userData.getPosition().setDirX(direction.getX());
            userData.getPosition().setDirY(direction.getY());
            userData.getPosition().setTime(nowTime);
            // 广播下
            addPlayerPosition(userData.getPlaceId(), userData.getUserId(), userData.getPosition());
        }
    }

    /**
     * 计算npc位置
     */
    public void npcMoveHandler(CrossFeastPvpUserData userData) {
        if (userData == null || !userData.isLive()) {
            return;
        }
        long nowTime = System.currentTimeMillis();

        // 拷贝一个出来计算
        CrossFeastPvpPosition position = userData.getPosition().clone();
        // 每毫秒的移动速度
        FeastStateConfig feastStateConfig = config.getStateConfigMap().get(userData.getPvpProperty().getStateId());
        double speed = feastStateConfig.getPvpSpeed() * 1.0 / 1000;
        double offsetTime = nowTime - position.getTime();
        double oldX = position.getX();
        double dx = position.getDirX();
        double offsetX = dx * speed * offsetTime;
        FeastPvpPlaceConfig placeConfig = config.getPlaceConfigMap().get(userData.getPlaceId());
        position.setX(calcX( oldX + offsetX, placeConfig));
        double oldY = position.getY();
        double dy = position.getDirY();
        double offsetY = dy * speed * offsetTime;
        position.setY(calcY( oldY + offsetY, placeConfig));
        position.setTime(nowTime);

        // 处理移动
        playerMoveHandler(userData, position, true);
    }

    private Coordinate randomDir() {
        double x = randomHelper.nextDouble(-1, 1);
        double y = (Double) randomHelper.randomList(calcDirY(x));
        return new Coordinate(x, y);
    }

    public List<Double> calcDirY(double dirX) {
        List<Double> list = new ArrayList<>();
        double sqrt = Math.sqrt(1 - dirX * dirX);
        list.add(sqrt);
        list.add(-sqrt);
        return list;
    }

    /**
     * 广播位置
     */
    private void addPlayerPosition(int roomId, long userId, CrossFeastPvpPosition position) {
        synchronized (needSyncPlayerPositionMap) {
            Map<Long, CrossFeastPvpPosition> roomMap = needSyncPlayerPositionMap.getOrDefault(roomId, new ConcurrentHashMap<>());
            roomMap.put(userId, position.clone());
            needSyncPlayerPositionMap.put(roomId, roomMap);
        }
    }

    /**
     * 计算x轴坐标
     */
    public double calcX(double x, FeastPvpPlaceConfig placeConfig, double radius) {
        return Math.max(roomMinX(placeConfig) + radius, Math.min(roomMaxX(placeConfig) - radius, x));
    }

    /**
     * 计算y轴坐标
     */
    public double calcY(double y, FeastPvpPlaceConfig placeConfig, int radius) {
        return Math.max(roomMinY(placeConfig) + radius, Math.min(roomMaxY(placeConfig) - radius, y));
    }

    /**
     * 计算x轴坐标
     */
    public double calcX(double x, FeastPvpPlaceConfig placeConfig) {
        return Math.max(roomMinX(placeConfig), Math.min(roomMaxX(placeConfig), x));
    }

    /**
     * 计算y轴坐标
     */
    public double calcY(double y, FeastPvpPlaceConfig placeConfig) {
        return Math.max(roomMinY(placeConfig), Math.min(roomMaxY(placeConfig), y));
    }

    /**
     * x轴最小变界
     * @param placeConfig 地图
     */
    public double roomMinX(FeastPvpPlaceConfig placeConfig) {
        return -placeConfig.getMapSizeList().get(0) / 2;
    }

    public double roomMaxX(FeastPvpPlaceConfig placeConfig) {
        return placeConfig.getMapSizeList().get(0) / 2;
    }

    public double roomMinY(FeastPvpPlaceConfig placeConfig) {
        return -placeConfig.getMapSizeList().get(1) / 2;
    }

    public double roomMaxY(FeastPvpPlaceConfig placeConfig) {
        return placeConfig.getMapSizeList().get(1) / 2;
    }

    /**
     * 待同步的位置信息
     */
    private Map<Integer, Map<Long, CrossFeastPvpPosition>> needSyncPlayerPositionMap = new ConcurrentHashMap<>();


    /**
     * 位置定时同步
     * 帧同步
     * 33ms
     * 1秒30帧
     */
    public void syncPositionTask() {
        for (Integer roomId : pvpPlaceDataMap.keySet()) {
            Map<Long, CrossFeastPvpPosition> playerMap;
            ConcurrentHashSet<Long> roomUserListSync = getRoomUserListSync(roomId);
            synchronized (needSyncPlayerPositionMap) {
                playerMap = needSyncPlayerPositionMap.getOrDefault(roomId, new ConcurrentHashMap<>());
                needSyncPlayerPositionMap.put(roomId, new ConcurrentHashMap<>());
            }
            // 玩家位置
            ShanHeFeastProto.FeastPvpRoomPositionSync.Builder syncMsg = ShanHeFeastProto.FeastPvpRoomPositionSync.newBuilder();
            for (Map.Entry<Long, CrossFeastPvpPosition> entry : playerMap.entrySet()) {
                ShanHeFeastProto.FeastPvpSimplePositionTemp.Builder temp = ShanHeFeastProto.FeastPvpSimplePositionTemp.newBuilder();
                temp.setUserId(entry.getKey());
                temp.setPosition(parseFeastPvpPlayerPositionData(entry.getValue()));
                syncMsg.addPosition(temp);
            }
            // 有变动才发
            if (syncMsg.getPositionCount() > 0) {
                sendPacketToAll(Protocol.U_SHAN_HE_FEAST_PVP_POSITION, syncMsg, roomUserListSync);
            }
        }
    }

    /**
     * 消息同步调用这个方法！！！
     * <p>
     * 排除心跳时间大于10s的
     *
     * @param roomId 房间id  id 传-1则获取活动内所有玩家
     */
    private ConcurrentHashSet<Long> getRoomUserListSync(int roomId) {
        ConcurrentHashSet<Long> list = new ConcurrentHashSet<>();
        long nowTime = System.currentTimeMillis();
        ConcurrentHashSet<Long> roomUserList;
        if (roomId == -1) {
            roomUserList = new ConcurrentHashSet<>(pvpUserDataMap.keySet());
        } else {
            roomUserList = getRoomUserList(roomId);
        }
        for (Long targetUserId : roomUserList) {
            CrossFeastPvpUserData userData = getPvpUserData(targetUserId);
            if(userData == null){
                continue;
            }
            if(userData.getPlaceId() != roomId){
                continue;
            }
            if (!userData.isApply() || !userData.isPvpAble() || npcUserMap.containsKey(userData.getUserId()) || robotUserMap.containsKey(userData.getUserId())) {
                continue;
            }
            if (userData.getLastPingPlaceTime() == -1 || nowTime - userData.getLastPingPlaceTime() > 10 * DateHelper.SECOND_MILLIONS) {
                continue;
            }
            list.add(targetUserId);
        }
        return list;
    }

    public static ShanHeFeastProto.FeastPvpPositionTemp.Builder parseFeastPvpPlayerPositionData(CrossFeastPvpPosition position) {
        if (position == null) {
            return null;
        }
        ShanHeFeastProto.FeastPvpPositionTemp.Builder builder = ShanHeFeastProto.FeastPvpPositionTemp.newBuilder();
        builder.setX((int) Math.floor(position.getX() * 10000));
        builder.setY((int) Math.floor(position.getY() * 10000));
        builder.setDirX((int) Math.floor(position.getDirX() * 10000));
        builder.setDirY((int) Math.floor(position.getDirY() * 10000));
        builder.setTime(position.getTime());
        return builder;
    }

    /**
     * 复活定时任务
     */
    public void activityPvpReviveTask() {
        if (!isBattleTime() || crossFeastPvpData.isSettle()) {
            return;
        }
        for (Integer roomId : pvpPlaceDataMap.keySet()) {
            ConcurrentHashSet<Long> roomUserList = getRoomUserList(roomId);
            for (Long userId : roomUserList) {
                handleRevive(getPvpUserData(userId));
            }
        }
    }

    /**
     * 处理复活逻辑
     * 处理降级逻辑
     * 处理升级逻辑
     */
    public void handleRevive(CrossFeastPvpUserData userData) {
        if (userData == null || !userData.isPvpAble()) {
            return;
        }
        long nowTime = System.currentTimeMillis();

        if(userData.isLive()){
            return;
        }

        boolean change = false;

        //没血量才处理复活
        if(userData.getPvpProperty().getHp() <= 0 &&  nowTime > userData.getReviveTime()){
            synchronized (getPlaceLock(userData.getPlaceId())) {
                if(userData.getPvpProperty().getHp() <= 0 &&  nowTime > userData.getReviveTime()) {
                    // 加个无敌时间
                    userData.setProtectTime(nowTime + config.getFEAST_PVP_CHANGE_PLACE_PROTECT_TIME() * DateHelper.SECOND_MILLIONS);
                    userData.setReviveCnt(userData.getReviveCnt() + 1);
//                    if (Config.isDebug()) {
//                        CrossFeastMgr.getLogger().error("房间[{}], 玩家[{}],复活", userData.getPlaceId(), userData.getUserId());
//                    }
                    change = true;

                    afterBirth(userData, nowTime);
                    //加入
                    sendJoinPositionSyncMsg(userData);
                }
            }
        }
        if(userData.getDownDemandTime() > 0 && nowTime > userData.getDownDemandTime()){
            synchronized (getPlaceLock(userData.getPlaceId())) {
                // 加个无敌时间
//                userData.setProtectTime(nowTime + config.getFEAST_PVP_CHANGE_PLACE_PROTECT_TIME() * DateHelper.SECOND_MILLIONS);
                userData.setUpDownDemand(false);
                removeRoomUser(userData.getPlaceId(), userData.getUserId());
                userData.setDownDemandTime(0);
                userData.setPlaceId(userData.getPlaceId() - 1);

                //本层数据
                userData.setKillCnt(0);
                userData.setReviveCnt(0);
                userData.setLockTarget(CrossFeastPvpLockTarget.EMPTY);

//                if(Config.isDebug()) {
//                    CrossFeastMgr.getLogger().error("房间[{}], 玩家[{}],降级", userData.getPlaceId(), userData.getUserId());
//                }
            }
            synchronized (getPlaceLock(userData.getPlaceId())) {
                addRoomUser(userData.getPlaceId(), userData.getUserId());
            }

            //离开
            ShanHeFeastProto.FeastLeavePlaceSync.Builder leaveMsg = ShanHeFeastProto.FeastLeavePlaceSync.newBuilder();
            leaveMsg.setType(2);
            leaveMsg.setUserId(userData.getUserId());
            sendPacketToAll(Protocol.U_SHAN_HE_FEAST_PVP_LEAVE_ROOM_SYNC, leaveMsg, getRoomUserListSync(userData.getPlaceId() + 1));

            //afterBirth(userData, nowTime);

            //加入
            sendJoinPositionSyncMsg(userData);

            change = true;

        }
        if(userData.getUpDemandTime() > 0 && nowTime > userData.getUpDemandTime()){

            synchronized (getPlaceLock(userData.getPlaceId())) {
                // 加个无敌时间
                userData.setProtectTime(nowTime + config.getFEAST_PVP_CHANGE_PLACE_PROTECT_TIME() * DateHelper.SECOND_MILLIONS);
                userData.setUpDownDemand(false);
                removeRoomUser(userData.getPlaceId(), userData.getUserId());
                userData.setUpDemandTime(0);
                userData.setPlaceId(userData.getPlaceId() + 1);
//                if(Config.isDebug()) {
//                    CrossFeastMgr.getLogger().error("房间[{}], 玩家[{}],晋级", userData.getPlaceId(), userData.getUserId());
//                }
                //本层数据
                userData.setKillCnt(0);
                userData.setReviveCnt(0);
                userData.setLockTarget(CrossFeastPvpLockTarget.EMPTY);
            }
            synchronized (getPlaceLock(userData.getPlaceId())) {
                addRoomUser(userData.getPlaceId(), userData.getUserId());
            }
            change = true;

            //离开
            ShanHeFeastProto.FeastLeavePlaceSync.Builder leaveMsg = ShanHeFeastProto.FeastLeavePlaceSync.newBuilder();
            leaveMsg.setType(1);
            leaveMsg.setUserId(userData.getUserId());
            sendPacketToAll(Protocol.U_SHAN_HE_FEAST_PVP_LEAVE_ROOM_SYNC, leaveMsg, getRoomUserListSync(userData.getPlaceId() - 1));

            afterBirth(userData, nowTime);

            //加入
            sendJoinPositionSyncMsg(userData);
        }

        if(!change){
            //没到时间
            return;
        }

        // 同步下
        ShanHeFeastProto.FeastEnterPvpRespMsg.Builder builder = ShanHeFeastProto.FeastEnterPvpRespMsg.newBuilder();
        builder.setRet(0);
        builder.setAble(userData.isPvpAble());
        // 用户数据
        builder.setPvpUserData(parseFeastPvpUserDataTemp(userData));
        // 房间信息
        ShanHeFeastProto.FeastPvpPlaceInfoTemp.Builder placeInfoTemp = parseFeastPvpPlaceInfoTemp(getPvpPlace(userData.getPlaceId()), userData.getUserId());
        if (placeInfoTemp != null) {
            builder.setPlace(placeInfoTemp);
        }
        sendPacket(ClientProtocol.U_SHAN_HE_FEAST_PLACE_STATE_CHANGE, builder, userData.getUserId());
    }

    private void afterBirth(CrossFeastPvpUserData userData, long nowTime) {
        //本条命数据
        userData.setBattleRecord(new CrossFeastPvpBattleRecord());

        // 属性更新
        updatePvpProperty(userData);

        //出生点
        FeastPvpBirthData birthData = randomBirth(userData.getPlaceId());
        if (birthData == null) {
            // 找不到出生点
            return;
        }
        FeastPvpPlaceConfig feastPvpPlaceConfig = config.getPlaceConfigMap().get(userData.getPlaceId());
        // 更新下位置
        userData.getPosition().setX(calcX(birthData.getCoordinate().getX(), feastPvpPlaceConfig, userData.getProfileRadius()));
        userData.getPosition().setY(calcY(birthData.getCoordinate().getY(), feastPvpPlaceConfig, userData.getProfileRadius()));
        userData.getPosition().setDirX(0);
        userData.getPosition().setDirY(0);
        userData.getPosition().setTime(nowTime);

        userData.setUpdateOption();

        // 广播位置
        addPlayerPosition(userData.getPlaceId(), userData.getUserId(), userData.getPosition());
    }

    //通知有玩家加入
    public void sendJoinPositionSyncMsg(CrossFeastPvpUserData userData) {
        //加入
        ShanHeFeastProto.FeastEnterPlaceSync.Builder syncMsg = ShanHeFeastProto.FeastEnterPlaceSync.newBuilder();
        ShanHeFeastProto.FeastPvpOtherUserTemp.Builder otherInfo = parseFeastPvpOtherUserTemp(userData);
        if (otherInfo != null) {
            syncMsg.setUser(otherInfo);
            sendPacketToAll(Protocol.U_SHAN_HE_FEAST_PVP_JOIN_ROOM_SYNC, syncMsg, getRoomUserListSync(userData.getPlaceId()));
//            if(Config.isDebug() && userData.getPlaceId() == 1) {
//                CrossFeastMgr.getLogger().debug("{},加入房间{}", userData.getUserId(), userData.getPlaceId());
//            }
        }
    }

    /**
     * 随机出生点 房间内
     */
    private FeastPvpBirthData randomBirth(int placeId) {
        CrossFeastPvpPlaceData roomData = pvpPlaceDataMap.get(placeId);
        if (roomData == null) {
            return null;
        }
        List<FeastPvpBirthData> list = new ArrayList<>();
        int minBirthCnt = Integer.MAX_VALUE;
        for (FeastPvpBirthData birthData : roomData.getBirthDataList()) {
            if (birthData.getBirthCnt() > minBirthCnt) {
                continue;
            }
            if (birthData.getBirthCnt() < minBirthCnt) {
                minBirthCnt = birthData.getBirthCnt();
                list.clear();
            }
            list.add(birthData);
        }
        FeastPvpBirthData birthData = list.get(randomHelper.next(0, list.size()));
        birthData.setBirthCnt(birthData.getBirthCnt() + 1);
        return birthData;
    }


    /**
     * 检测结算
     */
    public void checkSettleTask() {
        if (crossFeastPvpData.isSettle()) {
            return;
        }
        if (!isBattleEndTime()){
            return;
        }
        // 触发结算
        settle();

        // 清除房间内数据，释放内存
        for (CrossFeastPvpPlaceData roomData : pvpPlaceDataMap.values()) {
            roomData.clearData();
        }

        // 同步活动结束
        ShanHeFeastProto.CrossFeastPvpActivityDataSync.Builder builder = ShanHeFeastProto.CrossFeastPvpActivityDataSync.newBuilder();
        builder.setActivityId(config.getActivityInfo().getActivityId());
        builder.setRound(getCurRound());
        builder.setState(1);
        sendPacketToAll(Protocol.S_CROSS_SHAN_HE_FEAST_GET_ACTIVITY_DATA, builder, pvpUserDataMap.keySet());
    }

    /**
     * 结算
     */
    private void settle() {
        if (crossFeastPvpData.isSettle()) {
            return;
        }

        List<ShanHeFeastProto.FeastRankTempMsg> list = new ArrayList<>();
        int curRound = getCurRound();
        CrossFeastRankListModel roundRank = getRoundRank(curRound);
        synchronized (lock) {
            if (crossFeastPvpData.isSettle()) {
                return;
            }
            long nowTime = System.currentTimeMillis();
            // 标识结算
            crossFeastPvpData.setSettle(true);
            int rankNum = 0;
            for (CrossFeastRank rank : roundRank.getRankList()) {
                rankNum++;
                CrossFeastPvpUserData userData = getPvpUserData(Long.valueOf(rank.getId()));
                if (userData == null) {
                    continue;
                }
                ShanHeFeastProto.FeastRankTempMsg.Builder rankBuilder = ShanHeFeastProto.FeastRankTempMsg.newBuilder();
                rankBuilder.setValue(String.valueOf(rank.getValue()));
                rankBuilder.setParam(rank.getParam());
                rankBuilder.setUserId(Long.valueOf(rank.getId()));
                UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(rankBuilder.getUserId());
                if (userBaseInfo != null) {
                    rankBuilder.setPlayerBaseData(PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo));
                    list.add(rankBuilder.build());
                }

                // 记录下日志
                CrossAutoLogMgr.add(new LogFeastPvpSettle(
                        config.getActivityInfo().getActivityId(),
                        crossFeastPvpData.getRound(),
                        userData.getUserId(),
                        userData.getPlaceId(),
                        userData.getPvpProperty().getStateId(),
                        userData.getPvpProperty().getAbility(),
                        JSON.toJSONString(userData.getPvpProperty().getAttrMap()),
                        rank.getValue(),
                        rank.getParam(),
                        rankNum,
                        rank.getTime()
                ));
            }
        }
        ArrayList<Long> userList = new ArrayList<>(inPvpActivity);
        for (Long uid : userList) {
            ShanHeFeastProto.FeastSettleSyncMsg.Builder syncMsg = getEndBuilder(list, curRound, roundRank, uid);
            sendPacket(Protocol.U_SHAN_HE_FEAST_PVP_SETTLE_SYNC, syncMsg, uid);
        }

        //所有人推送一次当前轮次的积分
        for (Map.Entry<Long, CrossFeastPvpUserData> entry : pvpUserDataMap.entrySet()) {
            CrossFeastPvpUserData userData = entry.getValue();
            if(!userData.isPvpAble()){
                continue;
            }
            CrossFeastPvpBattleRecord roundBattleRecord = userData.getRoundBattleRecordMap().get(curRound);
            if(roundBattleRecord != null){
                notifyConditionChange(userData.getUserId(), eGamePlayerEventType.FeastPersonalScore, roundBattleRecord.getTotalScore(), curRound);
            }
        }
    }

    public ShanHeFeastProto.FeastSettleSyncMsg.Builder getEndBuilder(List<ShanHeFeastProto.FeastRankTempMsg> list, int curRound, CrossFeastRankListModel roundRank, Long uid) {
        ShanHeFeastProto.FeastSettleSyncMsg.Builder syncMsg = ShanHeFeastProto.FeastSettleSyncMsg.newBuilder();
        CrossFeastPvpUserData userData = getPvpUserData(uid);
        syncMsg.setMyRank(roundRank.getMyRank(String.valueOf(uid)));
        CrossFeastPvpBattleRecord battleRecord = userData.getRoundBattleRecordMap().get(curRound);
        if(battleRecord != null) {
            syncMsg.setValue(String.valueOf(battleRecord.getKill()));
            syncMsg.setParam(String.valueOf(battleRecord.getTotalScore()));
        }
        syncMsg.addAllSettle(list);
        return syncMsg;
    }

    public void crossMountAllotTask() {

        long nowTime = System.currentTimeMillis();

        // 当活动还没开始时候不分配
        if (!ActivityHelper.activityInTime(config.getActivityInfo())) {
            return;
        }

        // 大于等于活动结束时间不分配(最后一轮活动结束了，不进行分配)
        long nextAllotTime = getNextAllotTime(nowTime);
        if (nextAllotTime >= config.getActivityInfo().getEndTime()) {
            return;
        }
        long allotId = getCurAllotTime(nowTime);

        // 活动开始第一次不分配
        if (allotId == config.getActivityInfo().getBeginTime()) {
            return;
        }

        // 超过一分钟不分配
        if (nowTime / 1000 > (allotId + 60)) {
            return;
        }

        // 如果已经生成过就不再执行分配逻辑
        if (mountAllotDataMap.containsKey(allotId)) {
            return;
        }

        //只要锁定有加成的
        int maxRank = 0;
        for (Map.Entry<Integer, Integer> entry : config.getRankAdditionMap().entrySet()) {
            if(entry.getKey() > maxRank){
                maxRank = entry.getKey();
            }
        }

        int num = 0;
        Map<Long, Integer> userRankMap = new HashMap<>();
        LinkedList<CrossFeastRank> rankList = userPowerRank.getRankList();
        for (CrossFeastRank rank : rankList) {
            num++;
            if(num > maxRank){
                break;
            }
            userRankMap.put(Long.valueOf(rank.getId()), num);
        }
        allotMap.put(allotId, userRankMap);

        // 新增分配信息
        CrossFeastMountAllotData mountAllotData = mountAllotDataMap.get(allotId);
        if (mountAllotData == null) {
            mountAllotData = new CrossFeastMountAllotData();
            mountAllotData.setActivityId(config.getActivityInfo().getActivityId());
            mountAllotData.setAllotTimeId(allotId);
            mountAllotData.setAckServerIdList(new ArrayList<>());
            mountAllotData.setInsertOption();
            mountAllotDataMap.put(allotId, mountAllotData);
        }

        // 同步灵峰分配
        crossSyncMountAllotTask();

    }

    public void crossSyncMountAllotTask() {
        // 是否是活动结束期（+100s）不进行定时任务
        long nowTime = System.currentTimeMillis() / 1000;
        if (nowTime > (config.getActivityInfo().getEndTime() + 100)) {
            return;
        }

        // 检测是否同步完成 (兼容同步旧的分配)
        for ( Map.Entry<Long, CrossFeastMountAllotData> entryAllotData : mountAllotDataMap.entrySet()) {
            long temAllotId = entryAllotData.getKey();
            CrossFeastMountAllotData mountAllotData = entryAllotData.getValue();
            List<Long> serverIdList = config.getActivityInfo().getServerIdList();
            List<Long> needServerList = new ArrayList<>();
            for (Long serverId : serverIdList) {
                if (mountAllotData.getAckServerIdList().contains(serverId)) {
                    continue;
                }
                needServerList.add(serverId);
            }
            if (needServerList.size() == 0) {
                // 同步完毕
                continue;
            }
            // 封装同步
            Map<Long, Integer> curAllotMap = allotMap.get(temAllotId);
            if (curAllotMap == null) {
                continue;
            }
            Map<Long, List<ShanHeFeastProto.FeastUserMountAllotInfoTemp>> serverUserMap = new ConcurrentHashMap<>();

            for (Map.Entry<Long, Integer> entry : curAllotMap.entrySet()) {
                long userId = entry.getKey();
                UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(userId);
                if (null == userBaseInfo) {continue;}
                if (!needServerList.contains(userBaseInfo.getServerId())) {
                    continue;
                }
                if (!serverUserMap.containsKey(userBaseInfo.getServerId())) {
                    serverUserMap.put(userBaseInfo.getServerId(), new ArrayList<>());
                }
                ShanHeFeastProto.FeastUserMountAllotInfoTemp.Builder infoTemp = ShanHeFeastProto.FeastUserMountAllotInfoTemp.newBuilder();
                infoTemp.setUserId(userId);
                infoTemp.setMountId(entry.getValue());
                infoTemp.setActivityId(config.getActivityInfo().getActivityId());
                serverUserMap.get(userBaseInfo.getServerId()).add(infoTemp.build());
            }

            for (Long serverId : needServerList) {
                ShanHeFeastProto.CrossFeastSyncAllotMountMsg.Builder respMsg = ShanHeFeastProto.CrossFeastSyncAllotMountMsg.newBuilder();
                respMsg.setCurAllotTime(temAllotId);
                respMsg.setActivityId(config.getActivityInfo().getActivityId());
                List<ShanHeFeastProto.FeastUserMountAllotInfoTemp> allotInfoList = serverUserMap.get(serverId);
                if (allotInfoList != null) {
                    respMsg.addAllUserAllotList(allotInfoList);
                }
                YanQuMessage message = YanQuMessageUtils.buildMessage(GameProtocol.S_SHAN_HE_FEAST_SYNC_ALLOT_MOUNT_FROM_CROSS, respMsg);
                MessageHelper.sendPacket(serverId, 0, message);
                CrossFeastMgr.getLogger().info("活动{}，同步分配{} 加成，区服{} ", config.getActivityInfo().getActivityId(), temAllotId, serverId);
            }
        }
    }

    /**
     * 区服确认同步灵峰分配
     */
    public void ackMountAllotByCmd(long serverId, long allotId) {
        synchronized (mountAllotDataMap) {
            CrossFeastMountAllotData mountAllotData = mountAllotDataMap.get(allotId);
            if (mountAllotData == null) {
                return;
            }
            List<Long> atkServerList = mountAllotData.getAckServerIdList();
            if (atkServerList.contains(serverId)) {
                return;
            }
            atkServerList.add(serverId);
            mountAllotData.setAckServerIdList(atkServerList);
        }
    }

    /**
     * 修复
     */
    public void repair(){
        reloadConfig();
    }

    /**
     * 活动是否开启
     */
    public boolean isActivityOpenTime() {
        return ActivityHelper.activityInTime(config.getActivityInfo());
    }

    /**
     * 是否在报名期
     */
    protected boolean isApplyTime() {
        if(!isActivityOpenTime()){
            return false;
        }
        long nowTime = System.currentTimeMillis();
        long zeroTimeStamp = DateHelper.getTodayZeroTimeStamp();
        List<Integer> enterNameTimeList = config.getEnterNameTimeList();
        long startTimeStamp = zeroTimeStamp + enterNameTimeList.get(0) * DateHelper.SECOND_MILLIONS;
        long endTimeStamp = zeroTimeStamp + enterNameTimeList.get(1) * DateHelper.SECOND_MILLIONS;
        if(crossFeastPvpData.getRound() > 1){
            return nowTime >= zeroTimeStamp && nowTime <= endTimeStamp;
        }
        return nowTime >= startTimeStamp && nowTime <= endTimeStamp;
    }

    /**
     * 是否在准备期
     */
    public boolean isBattlePrepareTime(){
        long nowTime = System.currentTimeMillis();
        return isActivityOpenTime() && nowTime >= getPrepareStartTime() && nowTime < getPrepareEndTime();
    }

    /**
     * 活动是否战斗中
     */
    public boolean isBattleTime() {
        long nowTime = System.currentTimeMillis();
        return isActivityOpenTime() && nowTime >= getPrepareEndTime() && nowTime <= getBattleEndTime();
    }

    /**
     * 准备开始时间
     */
    public long getPrepareStartTime(){
        long zeroTimeStamp = DateHelper.getTodayZeroTimeStamp();
        return zeroTimeStamp + config.getPvpPrepareTimeList().get(0) * DateHelper.SECOND_MILLIONS;
    }

    /**
     * 准备结束时间
     */
    public long getPrepareEndTime(){
        return getPrepareStartTime() + config.getPvpPrepareTimeList().get(1) * DateHelper.SECOND_MILLIONS;
    }

    /**
     * 战斗期开始
     */
    protected long getBattleStartTime() {
        return getPrepareEndTime();
    }

    public boolean isBattleEndTime(){
        long nowTime = System.currentTimeMillis();
        return isActivityOpenTime() && nowTime > getBattleEndTime();
    }

    /**
     * 战斗期结束
     */
    protected long getBattleEndTime() {
        return getBattleStartTime() + config.getPvpBattleTimeEndCondition().get(0) * DateHelper.SECOND_MILLIONS;
    }

    /**
     * 获得玩家头像半径
     */
    public int getProfileRadius(CrossFeastPvpUserData userData, boolean update){
        if(userData.getProfileRadius() == 0 || update){
            List<String> radiusList = StringUtils.stringToStringList(config.getFEAST_PVP_PROFILE_RADIUS(), "\\|");
            int radius = 0;
            for (String radiusParam : radiusList) {
                String[] split = radiusParam.split(";");
                long configAbility = Long.parseLong(split[0]);
                if (userData.getPvpProperty().getStateId() >= configAbility) {
                    radius = Integer.parseInt(split[1]);
                }
            }
            userData.setProfileRadius(radius);
        }
        return userData.getProfileRadius();
    }

    /**
     * 获取下一次分配时间
     */
    private long getNextAllotTime(long time) {
        return getCurAllotTime(time) + config.getFEAST_PEAK_ASSIGN_CD();
    }

    /**
     * 获取当前分配时间 假设时间是0点01分 这边取到的时间是当前这一分配期的标识
     */
    private long getCurAllotTime(long time) {
        long nowTime = time / 1000;
        int allotCount = (int)Math.floor((double)(nowTime - config.getActivityInfo().getBeginTime()) / config.getFEAST_PEAK_ASSIGN_CD());
        // 当前的
        long tempAllotTimeId = config.getActivityInfo().getBeginTime() + allotCount * config.getFEAST_PEAK_ASSIGN_CD();
        if (tempAllotTimeId < config.getActivityInfo().getBeginTime()) {
            tempAllotTimeId = config.getActivityInfo().getBeginTime();
        }
        return tempAllotTimeId;
    }

    /**
     * 积分产出
     */
    private long lastOutputTime = System.currentTimeMillis();

    public void placeOutput() {
        if(!isActivityOpenTime()){
            return;
        }
        long nowTime = System.currentTimeMillis();
        long battleStartTime = getBattleStartTime();
        long battleEndTime = getBattleEndTime();
        if(nowTime < battleStartTime || nowTime > battleEndTime){
            return;
        }
        if(lastOutputTime < battleStartTime){
            lastOutputTime = battleStartTime;
        }

        long cdNum = (nowTime - lastOutputTime) / (config.getFEAST_PVP_AUTO_GET_SCORE_CD() * DateHelper.SECOND_MILLIONS);

        if(cdNum <= 0){
            return;
        }

        lastOutputTime += cdNum * config.getFEAST_PVP_AUTO_GET_SCORE_CD() * DateHelper.SECOND_MILLIONS;

        //已计算的玩家
        Set<Long> userSet = new HashSet<>();

        //按报名的排行开始计算
        for (CrossFeastRank rank : applyRankListModel.getRankList()) {
            long uid = Long.valueOf(rank.getId());
            if(isNpc(uid) || isRobot(uid)){
                continue;
            }
            if(userSet.contains(uid)){
                continue;
            }
            CrossFeastPvpUserData pvpUserData = getPvpUserData(uid);
            if(pvpUserData == null || !pvpUserData.isPvpAble()){
                continue;
            }
            FeastPvpPlaceConfig placeConfig = config.getPlaceConfigMap().get(pvpUserData.getPlaceId());
            if(placeConfig == null){
                continue;
            }
            addBattleScore(uid, 2, placeConfig.getTimeScore() * cdNum, "");
            userSet.add(uid);
        }

    }
}
